/*      */ package com.zimbra.cs.imap;
/*      */ 
/*      */ import com.google.common.base.Charsets;
/*      */ import com.google.common.base.Strings;
/*      */ import com.google.common.collect.ImmutableSet;
/*      */ import com.google.common.collect.Lists;
/*      */ import com.google.common.io.Closeables;
/*      */ import com.zimbra.client.ZFolder;
/*      */ import com.zimbra.client.ZFolder.Color;
/*      */ import com.zimbra.client.ZFolder.View;
/*      */ import com.zimbra.client.ZGrant;
/*      */ import com.zimbra.client.ZGrant.GranteeType;
/*      */ import com.zimbra.client.ZMailbox;
/*      */ import com.zimbra.common.account.Key.AccountBy;
/*      */ import com.zimbra.common.account.Key.DistributionListBy;
/*      */ import com.zimbra.common.calendar.WellKnownTimeZones;
/*      */ import com.zimbra.common.localconfig.DebugConfig;
/*      */ import com.zimbra.common.localconfig.KnownKey;
/*      */ import com.zimbra.common.localconfig.LC;
/*      */ import com.zimbra.common.service.ServiceException;
/*      */ import com.zimbra.common.soap.SoapProtocol;
/*      */ import com.zimbra.common.util.AccessBoundedRegex;
/*      */ import com.zimbra.common.util.ArrayUtil;
/*      */ import com.zimbra.common.util.DateUtil;
/*      */ import com.zimbra.common.util.Log;
/*      */ import com.zimbra.common.util.Pair;
/*      */ import com.zimbra.common.util.StringUtil;
/*      */ import com.zimbra.common.util.ZimbraLog;
/*      */ import com.zimbra.cs.account.Account;
/*      */ import com.zimbra.cs.account.AccountServiceException;
/*      */ import com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException;
/*      */ import com.zimbra.cs.account.Config;
/*      */ import com.zimbra.cs.account.NamedEntry;
/*      */ import com.zimbra.cs.account.Provisioning;
/*      */ import com.zimbra.cs.account.Server;
/*      */ import com.zimbra.cs.account.auth.AuthContext.Protocol;
/*      */ import com.zimbra.cs.index.SearchParams;
/*      */ import com.zimbra.cs.index.SearchParams.Fetch;
/*      */ import com.zimbra.cs.index.SortBy;
/*      */ import com.zimbra.cs.index.ZimbraHit;
/*      */ import com.zimbra.cs.index.ZimbraQueryResults;
/*      */ import com.zimbra.cs.mailbox.ACL;
/*      */ import com.zimbra.cs.mailbox.ACL.Grant;
/*      */ import com.zimbra.cs.mailbox.Flag;
/*      */ import com.zimbra.cs.mailbox.Flag.FlagInfo;
/*      */ import com.zimbra.cs.mailbox.Folder;
/*      */ import com.zimbra.cs.mailbox.Folder.FolderOptions;
/*      */ import com.zimbra.cs.mailbox.MailItem;
/*      */ import com.zimbra.cs.mailbox.MailItem.Type;
/*      */ import com.zimbra.cs.mailbox.MailServiceException;
/*      */ import com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException;
/*      */ import com.zimbra.cs.mailbox.Mailbox;
/*      */ import com.zimbra.cs.mailbox.MailboxIndex;
/*      */ import com.zimbra.cs.mailbox.MailboxLock;
/*      */ import com.zimbra.cs.mailbox.Mountpoint;
/*      */ import com.zimbra.cs.mailbox.OperationContext;
/*      */ import com.zimbra.cs.mailbox.SearchFolder;
/*      */ import com.zimbra.cs.mailbox.Tag;
/*      */ import com.zimbra.cs.mailclient.imap.IDInfo;
/*      */ import com.zimbra.cs.security.sasl.Authenticator;
/*      */ import com.zimbra.cs.security.sasl.AuthenticatorUser;
/*      */ import com.zimbra.cs.security.sasl.PlainAuthenticator;
/*      */ import com.zimbra.cs.server.ServerThrottle;
/*      */ import com.zimbra.cs.service.mail.FolderAction;
/*      */ import com.zimbra.cs.service.mail.ItemActionHelper;
/*      */ import com.zimbra.cs.service.util.ItemId;
/*      */ import com.zimbra.cs.util.AccountUtil;
/*      */ import com.zimbra.cs.util.BuildInfo;
/*      */ import java.io.IOException;
/*      */ import java.io.OutputStream;
/*      */ import java.io.PrintStream;
/*      */ import java.net.InetSocketAddress;
/*      */ import java.net.URLEncoder;
/*      */ import java.nio.charset.Charset;
/*      */ import java.util.ArrayList;
/*      */ import java.util.Arrays;
/*      */ import java.util.Collection;
/*      */ import java.util.Collections;
/*      */ import java.util.Date;
/*      */ import java.util.HashMap;
/*      */ import java.util.HashSet;
/*      */ import java.util.Iterator;
/*      */ import java.util.LinkedHashMap;
/*      */ import java.util.LinkedHashSet;
/*      */ import java.util.LinkedList;
/*      */ import java.util.List;
/*      */ import java.util.Map;
/*      */ import java.util.Map.Entry;
/*      */ import java.util.Set;
/*      */ import java.util.TimeZone;
/*      */ import java.util.TreeMap;
/*      */ import java.util.concurrent.locks.ReentrantLock;
/*      */ import java.util.regex.Pattern;
/*      */ import javax.mail.MessagingException;
/*      */ import javax.mail.internet.MimeMessage;
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ abstract class ImapHandler
/*      */ {
/*      */   private static final long MAXIMUM_IDLE_PROCESSING_MILLIS = 15000L;
/*      */   
/*      */   static enum State
/*      */   {
/*  108 */     NOT_AUTHENTICATED,  AUTHENTICATED,  SELECTED,  LOGOUT;
/*      */     private State() {} }
/*  110 */   static enum ImapExtension { CONDSTORE,  QRESYNC;
/*      */     
/*      */     private ImapExtension() {}
/*      */   }
/*      */   
/*  115 */   private static final String ID_PARAMS = "\"NAME\" \"Zimbra\" \"VERSION\" \"" + BuildInfo.VERSION + "\" \"RELEASE\" \"" + BuildInfo.RELEASE + "\"";
/*      */   
/*      */ 
/*  118 */   static final char[] LINE_SEPARATOR = { '\r', '\n' };
/*  119 */   static final byte[] LINE_SEPARATOR_BYTES = { 13, 10 };
/*      */   
/*      */   ImapConfig config;
/*      */   
/*      */   OutputStream output;
/*      */   Authenticator authenticator;
/*      */   ImapCredentials credentials;
/*      */   boolean startedTLS;
/*      */   String lastCommand;
/*      */   int consecutiveError;
/*      */   private ImapProxy imapProxy;
/*      */   ImapSession selectedFolder;
/*      */   private String idleTag;
/*      */   private String origRemoteIp;
/*      */   private String via;
/*      */   private String userAgent;
/*      */   boolean goodbyeSent;
/*      */   private Set<ImapExtension> activeExtensions;
/*      */   private final ServerThrottle reqThrottle;
/*      */   private final ImapCommandThrottle commandThrottle;
/*  139 */   private static final Set<String> THROTTLED_COMMANDS = ImmutableSet.of("APPEND", "COPY", "CREATE", "EXAMINE", "FETCH", "LIST", new String[] { "LSUB", "UID", "SEARCH", "SELECT", "SORT", "STORE", "XLIST" });
/*      */   
/*      */ 
/*      */   ImapHandler(ImapConfig config)
/*      */   {
/*  144 */     this.config = config;
/*  145 */     this.startedTLS = config.isSslEnabled();
/*  146 */     this.reqThrottle = ServerThrottle.getThrottle(config.getProtocol());
/*  147 */     this.commandThrottle = new ImapCommandThrottle(LC.imap_throttle_command_limit.intValue());
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   ImapCredentials getCredentials()
/*      */   {
/*  171 */     return this.credentials;
/*      */   }
/*      */   
/*      */   ImapHandler setCredentials(ImapCredentials creds) {
/*  175 */     this.credentials = creds;
/*  176 */     return this;
/*      */   }
/*      */   
/*      */   public boolean isSSLEnabled() {
/*  180 */     return this.startedTLS;
/*      */   }
/*      */   
/*      */   public ImapConfig getConfig() {
/*  184 */     return this.config;
/*      */   }
/*      */   
/*      */ 
/*      */   String getOrigRemoteIp()
/*      */   {
/*  190 */     return this.origRemoteIp;
/*      */   }
/*      */   
/*      */   String getVia() {
/*  194 */     return this.via;
/*      */   }
/*      */   
/*      */   String getUserAgent() {
/*  198 */     return this.userAgent;
/*      */   }
/*      */   
/*      */   void setLoggingContext() {
/*  202 */     ZimbraLog.clearContext();
/*  203 */     ImapSession i4selected = this.selectedFolder;
/*  204 */     Mailbox mbox = i4selected == null ? null : i4selected.getMailbox();
/*      */     
/*  206 */     if (this.credentials != null) {
/*  207 */       ZimbraLog.addAccountNameToContext(this.credentials.getUsername());
/*      */     }
/*  209 */     if (mbox != null) {
/*  210 */       ZimbraLog.addMboxToContext(mbox.getId());
/*      */     }
/*  212 */     if (this.origRemoteIp != null) {
/*  213 */       ZimbraLog.addOrigIpToContext(this.origRemoteIp);
/*      */     }
/*  215 */     if (this.via != null) {
/*  216 */       ZimbraLog.addViaToContext(this.via);
/*      */     }
/*  218 */     if (this.userAgent != null) {
/*  219 */       ZimbraLog.addUserAgentToContext(this.userAgent);
/*      */     }
/*  221 */     ZimbraLog.addIpToContext(getRemoteIp());
/*      */   }
/*      */   
/*      */   protected void handleParseException(ImapParseException e) throws IOException {
/*  225 */     String message = (e.mCode == null ? "" : new StringBuilder().append('[').append(e.mCode).append("] ").toString()) + e.getMessage();
/*  226 */     if (e.mTag == null) {
/*  227 */       sendBAD(message);
/*  228 */     } else if (e.mNO) {
/*  229 */       sendNO(e.mTag, message);
/*      */     } else {
/*  231 */       sendBAD(e.mTag, message);
/*      */     }
/*      */   }
/*      */   
/*      */   void checkEOF(String tag, ImapRequest req) throws ImapParseException {
/*  236 */     if (!req.eof()) {
/*  237 */       throw new ImapParseException(tag, "excess characters at end of command");
/*      */     }
/*      */   }
/*      */   
/*      */   boolean continueAuthentication(ImapRequest req) throws IOException {
/*  242 */     String tag = getTag(this.authenticator);
/*      */     try
/*      */     {
/*  245 */       req.setTag(tag);
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*  250 */       if (req.peekChar() == 42) {
/*  251 */         req.skipChar('*');
/*  252 */         if (req.eof()) {
/*  253 */           sendBAD(tag, "AUTHENTICATE aborted");
/*      */         } else {
/*  255 */           sendBAD(tag, "AUTHENTICATE failed; invalid base64 input");
/*      */         }
/*  257 */         this.authenticator = null;
/*  258 */         return true;
/*      */       }
/*      */       
/*  261 */       byte[] response = req.readBase64(false);
/*  262 */       checkEOF(tag, req);
/*  263 */       return continueAuthentication(response);
/*      */     } catch (ImapParseException ipe) {
/*  265 */       sendBAD(tag, ipe.getMessage());
/*  266 */       this.authenticator = null; }
/*  267 */     return true;
/*      */   }
/*      */   
/*      */   private boolean continueAuthentication(byte[] response) throws IOException
/*      */   {
/*  272 */     this.authenticator.handle(response);
/*  273 */     if (this.authenticator.isComplete()) {
/*  274 */       if (this.authenticator.isAuthenticated())
/*      */       {
/*  276 */         completeAuthentication();
/*  277 */         enableInactivityTimer();
/*  278 */         return true;
/*      */       }
/*      */       
/*  281 */       boolean canContinue = canContinue(this.authenticator);
/*  282 */       this.authenticator = null;
/*  283 */       return canContinue;
/*      */     }
/*  285 */     return true;
/*      */   }
/*      */   
/*      */   boolean isIdle() {
/*  289 */     return this.idleTag != null;
/*      */   }
/*      */   
/*      */   private static String getTag(Authenticator auth) {
/*  293 */     return ((ImapAuthenticatorUser)auth.getAuthenticatorUser()).getTag();
/*      */   }
/*      */   
/*      */   private static boolean canContinue(Authenticator auth) {
/*  297 */     return ((ImapAuthenticatorUser)auth.getAuthenticatorUser()).canContinue();
/*      */   }
/*      */   
/*      */   boolean checkAccountStatus() {
/*  301 */     if (!this.config.isServiceEnabled()) {
/*  302 */       ZimbraLog.imap.warn("user services are disabled; dropping connection");
/*  303 */       return false;
/*      */     }
/*      */     
/*  306 */     if (this.credentials == null) {
/*  307 */       return true;
/*      */     }
/*      */     try {
/*  310 */       Account account = this.credentials.getAccount();
/*  311 */       if ((account == null) || (!account.isAccountStatusActive())) {
/*  312 */         ZimbraLog.imap.warn("account missing or not active; dropping connection");
/*  313 */         return false;
/*      */       }
/*      */     } catch (ServiceException e) {
/*  316 */       ZimbraLog.imap.warn("error checking account status; dropping connection", e);
/*  317 */       return false;
/*      */     }
/*      */     
/*      */ 
/*  321 */     ImapSession i4selected = this.selectedFolder;
/*  322 */     if (i4selected == null) {
/*  323 */       return true;
/*      */     }
/*  325 */     String id = i4selected.getTargetAccountId();
/*  326 */     if (this.credentials.getAccountId().equalsIgnoreCase(id)) {
/*  327 */       return true;
/*      */     }
/*      */     try {
/*  330 */       Account account = Provisioning.getInstance().get(Key.AccountBy.id, id);
/*  331 */       if ((account == null) || (!account.isAccountStatusActive())) {
/*  332 */         ZimbraLog.imap.warn("target account missing or not active; dropping connection");
/*  333 */         return false;
/*      */       }
/*      */     } catch (ServiceException e) {
/*  336 */       ZimbraLog.imap.warn("error checking target account status; dropping connection", e);
/*  337 */       return false;
/*      */     }
/*      */     
/*  340 */     return true;
/*      */   }
/*      */   
/*      */   boolean executeRequest(ImapRequest req) throws IOException, ImapException {
/*  344 */     boolean isProxied = this.imapProxy != null;
/*      */     
/*  346 */     if (getCredentials() != null) {
/*  347 */       if (this.reqThrottle.isAccountThrottled(getCredentials().getAccountId(), new String[] { getOrigRemoteIp(), getRemoteIp() })) {
/*  348 */         ZimbraLog.imap.warn("too many IMAP requests from account %s dropping connection", new Object[] { getCredentials().getAccountId() });
/*  349 */         throw new ImapThrottledException("too many requests for acct");
/*      */       }
/*      */     }
/*  352 */     if (this.reqThrottle.isIpThrottled(getOrigRemoteIp())) {
/*  353 */       ZimbraLog.imap.warn("too many IMAP requests from original remote ip %s dropping connection", new Object[] { getOrigRemoteIp() });
/*  354 */       throw new ImapThrottledException("too many requests from original ip"); }
/*  355 */     if (this.reqThrottle.isIpThrottled(getRemoteIp())) {
/*  356 */       ZimbraLog.imap.warn("too many IMAP requests from remote ip %s dropping connection", new Object[] { getRemoteIp() });
/*  357 */       throw new ImapThrottledException("too many requests from remote ip");
/*      */     }
/*      */     
/*  360 */     if (isIdle()) {
/*  361 */       boolean clean = false;
/*      */       try {
/*  363 */         clean = (req.readATOM().equals("DONE")) && (req.eof());
/*      */       } catch (ImapParseException ipe) {}
/*  365 */       return doIDLE(null, false, clean, req);
/*      */     }
/*      */     
/*  368 */     String tag = req.readTag();
/*      */     
/*  370 */     boolean byUID = false;
/*  371 */     req.skipSpace();
/*  372 */     String command = this.lastCommand = req.readATOM();
/*      */     do {
/*  374 */       if (!THROTTLED_COMMANDS.contains(command)) {
/*  375 */         this.commandThrottle.reset();
/*      */       }
/*  377 */       switch (command.charAt(0)) {
/*      */       case 'A': 
/*  379 */         if (command.equals("AUTHENTICATE")) {
/*  380 */           req.skipSpace();String mechanism = req.readATOM();
/*  381 */           byte[] response = null;
/*  382 */           if ((req.peekChar() == 32) && (extensionEnabled("SASL-IR"))) {
/*  383 */             req.skipSpace();
/*  384 */             response = req.readBase64(true);
/*      */           }
/*  386 */           checkEOF(tag, req);
/*  387 */           return doAUTHENTICATE(tag, mechanism, response); }
/*  388 */         if (command.equals("APPEND")) {
/*  389 */           List<AppendMessage> appends = new ArrayList(1);
/*  390 */           req.skipSpace();
/*  391 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*      */           do {
/*  393 */             req.skipSpace();
/*  394 */             appends.add(AppendMessage.parse(this, tag, req));
/*  395 */           } while ((!req.eof()) && (extensionEnabled("MULTIAPPEND")));
/*  396 */           checkEOF(tag, req);
/*  397 */           return doAPPEND(tag, path, appends);
/*      */         }
/*      */         break;
/*      */       case 'C': 
/*  401 */         if (command.equals("CAPABILITY")) {
/*  402 */           checkEOF(tag, req);
/*  403 */           return doCAPABILITY(tag); }
/*  404 */         if (command.equals("COPY")) {
/*  405 */           req.skipSpace();
/*  406 */           String sequence = req.readSequence();
/*  407 */           req.skipSpace();
/*  408 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*  409 */           checkEOF(tag, req);
/*  410 */           return isProxied ? this.imapProxy.proxy(req) : doCOPY(tag, sequence, path, byUID); }
/*  411 */         if (command.equals("CLOSE")) {
/*  412 */           checkEOF(tag, req);
/*  413 */           return doCLOSE(tag); }
/*  414 */         if (command.equals("CREATE")) {
/*  415 */           req.skipSpace();
/*  416 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*  417 */           checkEOF(tag, req);
/*  418 */           return doCREATE(tag, path); }
/*  419 */         if (command.equals("CHECK")) {
/*  420 */           checkEOF(tag, req);
/*  421 */           return doCHECK(tag);
/*      */         }
/*      */         break;
/*      */       case 'D': 
/*  425 */         if (command.equals("DELETE")) {
/*  426 */           req.skipSpace();
/*  427 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials, ImapPath.Scope.NAME);
/*  428 */           checkEOF(tag, req);
/*  429 */           return doDELETE(tag, path); }
/*  430 */         if ((command.equals("DELETEACL")) && (extensionEnabled("ACL"))) {
/*  431 */           req.skipSpace();
/*  432 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*  433 */           req.skipSpace();
/*  434 */           String principal = req.readAstring();
/*  435 */           checkEOF(tag, req);
/*  436 */           return doDELETEACL(tag, path, principal);
/*      */         }
/*      */         break;
/*      */       case 'E': 
/*  440 */         if (command.equals("EXPUNGE")) {
/*  441 */           String sequence = null;
/*  442 */           if (byUID) {
/*  443 */             req.skipSpace();
/*  444 */             sequence = req.readSequence();
/*      */           }
/*  446 */           checkEOF(tag, req);
/*  447 */           return isProxied ? this.imapProxy.proxy(req) : doEXPUNGE(tag, byUID, sequence); }
/*  448 */         if (command.equals("EXAMINE")) {
/*  449 */           byte params = 0;QResyncInfo qri = null;
/*  450 */           req.skipSpace();
/*  451 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*  452 */           if (req.peekChar() == 32) {
/*  453 */             req.skipSpace();req.skipChar('(');
/*  454 */             while (req.peekChar() != 41) {
/*  455 */               if (params != 0) {
/*  456 */                 req.skipSpace();
/*      */               }
/*  458 */               String param = req.readATOM();
/*  459 */               if ((param.equals("CONDSTORE")) && (extensionEnabled("CONDSTORE"))) {
/*  460 */                 params = (byte)(params | 0x2);
/*  461 */               } else if ((param.equals("QRESYNC")) && (sessionActivated(ImapExtension.QRESYNC))) {
/*  462 */                 params = (byte)(params | 0x2);
/*  463 */                 req.skipSpace();
/*  464 */                 qri = parseQResyncInfo(req);
/*      */               } else {
/*  466 */                 throw new ImapParseException(tag, "unknown EXAMINE parameter \"" + param + '"');
/*      */               }
/*      */             }
/*  469 */             req.skipChar(')');
/*      */           }
/*  471 */           checkEOF(tag, req);
/*  472 */           return doEXAMINE(tag, path, params, qri); }
/*  473 */         if ((command.equals("ENABLE")) && (extensionEnabled("ENABLE"))) {
/*  474 */           List<String> extensions = new ArrayList();
/*      */           do {
/*  476 */             req.skipSpace();
/*  477 */             extensions.add(req.readATOM());
/*  478 */           } while (!req.eof());
/*  479 */           checkEOF(tag, req);
/*  480 */           return doENABLE(tag, extensions);
/*      */         }
/*      */         break;
/*      */       case 'F': 
/*  484 */         if (command.equals("FETCH")) {
/*  485 */           List<ImapPartSpecifier> parts = new ArrayList();
/*  486 */           int modseq = -1;
/*  487 */           req.skipSpace();String sequence = req.readSequence();
/*  488 */           req.skipSpace();int attributes = req.readFetch(parts);
/*  489 */           if (req.peekChar() == 32) {
/*  490 */             boolean first = true;
/*  491 */             req.skipSpace();req.skipChar('(');
/*  492 */             while (req.peekChar() != 41) {
/*  493 */               if (!first) {
/*  494 */                 req.skipSpace();
/*      */               }
/*  496 */               String modifier = req.readATOM();
/*  497 */               if ((modifier.equals("CHANGEDSINCE")) && (extensionEnabled("CONDSTORE"))) {
/*  498 */                 req.skipSpace();modseq = req.parseInteger(req.readNumber(true));
/*  499 */               } else if ((modifier.equals("VANISHED")) && (byUID) && (sessionActivated(ImapExtension.QRESYNC))) {
/*  500 */                 attributes |= 0x200;
/*      */               } else {
/*  502 */                 throw new ImapParseException(tag, "bad FETCH modifier: " + modifier);
/*      */               }
/*  504 */               first = false;
/*      */             }
/*  506 */             req.skipChar(')');
/*      */           }
/*  508 */           checkEOF(tag, req);
/*  509 */           return isProxied ? this.imapProxy.proxy(req) : doFETCH(tag, sequence, attributes, parts, byUID, modseq);
/*      */         }
/*      */         break;
/*      */       case 'G': 
/*  513 */         if ((command.equals("GETQUOTA")) && (extensionEnabled("QUOTA"))) {
/*  514 */           req.skipSpace();
/*  515 */           ImapPath qroot = new ImapPath(req.readAstring(), this.credentials);
/*  516 */           checkEOF(tag, req);
/*  517 */           return doGETQUOTA(tag, qroot); }
/*  518 */         if ((command.equals("GETACL")) && (extensionEnabled("ACL"))) {
/*  519 */           req.skipSpace();
/*  520 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*  521 */           checkEOF(tag, req);
/*  522 */           return doGETACL(tag, path); }
/*  523 */         if ((command.equals("GETQUOTAROOT")) && (extensionEnabled("QUOTA"))) {
/*  524 */           req.skipSpace();
/*  525 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*  526 */           checkEOF(tag, req);
/*  527 */           return doGETQUOTAROOT(tag, path);
/*      */         }
/*      */         break;
/*      */       case 'I': 
/*  531 */         if ((command.equals("ID")) && (extensionEnabled("ID"))) {
/*  532 */           req.skipSpace();
/*  533 */           Map<String, String> params = req.readParameters(true);
/*  534 */           checkEOF(tag, req);
/*  535 */           return doID(tag, params); }
/*  536 */         if ((command.equals("IDLE")) && (extensionEnabled("IDLE"))) {
/*  537 */           checkEOF(tag, req);
/*  538 */           return doIDLE(tag, true, true, req);
/*      */         }
/*      */         break;
/*      */       case 'L': 
/*  542 */         if (command.equals("LOGIN")) {
/*  543 */           req.skipSpace();
/*  544 */           String user = req.readAstring();
/*  545 */           req.skipSpace();
/*  546 */           String pass = req.readAstring();
/*  547 */           checkEOF(tag, req);
/*  548 */           return doLOGIN(tag, user, pass); }
/*  549 */         if (command.equals("LOGOUT")) {
/*  550 */           checkEOF(tag, req);
/*  551 */           return doLOGOUT(tag); }
/*  552 */         if (command.equals("LIST")) {
/*  553 */           Set<String> patterns = new LinkedHashSet(2);
/*  554 */           boolean parenthesized = false;
/*  555 */           byte selectOptions = 0;byte returnOptions = 0;byte status = 0;
/*      */           
/*  557 */           req.skipSpace();
/*  558 */           if ((req.peekChar() == 40) && (extensionEnabled("LIST-EXTENDED"))) {
/*  559 */             req.skipChar('(');
/*  560 */             while (req.peekChar() != 41) {
/*  561 */               if (selectOptions != 0) {
/*  562 */                 req.skipSpace();
/*      */               }
/*  564 */               String option = req.readATOM();
/*  565 */               if (option.equals("RECURSIVEMATCH")) {
/*  566 */                 selectOptions = (byte)(selectOptions | 0x4);
/*  567 */               } else if (option.equals("SUBSCRIBED")) {
/*  568 */                 selectOptions = (byte)(selectOptions | 0x1);
/*  569 */               } else if (option.equals("REMOTE")) {
/*  570 */                 selectOptions = (byte)(selectOptions | 0x2);
/*      */               } else {
/*  572 */                 throw new ImapParseException(tag, "unknown LIST select option \"" + option + '"');
/*      */               }
/*      */             }
/*  575 */             if ((selectOptions & 0x5) == 4) {
/*  576 */               throw new ImapParseException(tag, "must include SUBSCRIBED when specifying RECURSIVEMATCH");
/*      */             }
/*  578 */             req.skipChar(')');
/*  579 */             req.skipSpace();
/*      */           }
/*      */           
/*  582 */           String base = req.readFolder();req.skipSpace();
/*      */           
/*  584 */           if ((req.peekChar() == 40) && (extensionEnabled("LIST-EXTENDED"))) {
/*  585 */             parenthesized = true;
/*  586 */             req.skipChar('(');
/*      */           }
/*      */           do {
/*  589 */             if (!patterns.isEmpty()) {
/*  590 */               req.skipSpace();
/*      */             }
/*  592 */             patterns.add(req.readFolderPattern());
/*  593 */           } while ((parenthesized) && (req.peekChar() != 41));
/*  594 */           if (parenthesized) {
/*  595 */             req.skipChar(')');
/*      */           }
/*  597 */           if ((req.peekChar() == 32) && (extensionEnabled("LIST-EXTENDED"))) {
/*  598 */             req.skipSpace();req.skipAtom("RETURN");
/*  599 */             req.skipSpace();req.skipChar('(');
/*  600 */             while (req.peekChar() != 41) {
/*  601 */               if (returnOptions != 0) {
/*  602 */                 req.skipSpace();
/*      */               }
/*  604 */               String option = req.readATOM();
/*  605 */               if (option.equals("SUBSCRIBED")) {
/*  606 */                 returnOptions = (byte)(returnOptions | 0x1);
/*  607 */               } else if (option.equals("CHILDREN")) {
/*  608 */                 returnOptions = (byte)(returnOptions | 0x2);
/*  609 */               } else if ((option.equals("STATUS")) && (extensionEnabled("LIST-STATUS"))) {
/*  610 */                 req.skipSpace();
/*  611 */                 status = parseStatusFields(req);
/*      */               } else {
/*  613 */                 throw new ImapParseException(tag, "unknown LIST return option \"" + option + '"');
/*      */               }
/*      */             }
/*  616 */             req.skipChar(')');
/*      */           }
/*  618 */           checkEOF(tag, req);
/*  619 */           return doLIST(tag, base, patterns, selectOptions, returnOptions, status); }
/*  620 */         if (command.equals("LSUB")) {
/*  621 */           req.skipSpace();
/*  622 */           String base = req.readFolder();
/*  623 */           req.skipSpace();
/*  624 */           String pattern = req.readFolderPattern();
/*  625 */           checkEOF(tag, req);
/*  626 */           return doLSUB(tag, base, pattern); }
/*  627 */         if ((command.equals("LISTRIGHTS")) && (extensionEnabled("ACL"))) {
/*  628 */           req.skipSpace();
/*  629 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*  630 */           req.skipSpace();
/*  631 */           String principal = req.readAstring();
/*  632 */           checkEOF(tag, req);
/*  633 */           return doLISTRIGHTS(tag, path, principal);
/*      */         }
/*      */         break;
/*      */       case 'M': 
/*  637 */         if ((command.equals("MYRIGHTS")) && (extensionEnabled("ACL"))) {
/*  638 */           req.skipSpace();
/*  639 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*  640 */           checkEOF(tag, req);
/*  641 */           return doMYRIGHTS(tag, path);
/*      */         }
/*      */         break;
/*      */       case 'N': 
/*  645 */         if (command.equals("NOOP")) {
/*  646 */           checkEOF(tag, req);
/*  647 */           return isProxied ? this.imapProxy.proxy(req) : doNOOP(tag); }
/*  648 */         if ((command.equals("NAMESPACE")) && (extensionEnabled("NAMESPACE"))) {
/*  649 */           checkEOF(tag, req);
/*  650 */           return doNAMESPACE(tag);
/*      */         }
/*      */         break;
/*      */       case 'R': 
/*  654 */         if (command.equals("RENAME")) {
/*  655 */           req.skipSpace();
/*  656 */           ImapPath folder = new ImapPath(req.readFolder(), this.credentials, ImapPath.Scope.NAME);
/*  657 */           req.skipSpace();
/*  658 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials, ImapPath.Scope.NAME);
/*  659 */           checkEOF(tag, req);
/*  660 */           return doRENAME(tag, folder, path);
/*      */         }
/*      */         break;
/*      */       case 'S': 
/*  664 */         if (command.equals("STORE")) {
/*  665 */           StoreAction operation = StoreAction.REPLACE;
/*  666 */           boolean silent = false;int modseq = -1;
/*  667 */           req.skipSpace();String sequence = req.readSequence();req.skipSpace();
/*      */           
/*  669 */           if ((req.peekChar() == 40) && (extensionEnabled("CONDSTORE"))) {
/*  670 */             req.skipChar('(');
/*  671 */             req.skipAtom("UNCHANGEDSINCE");
/*  672 */             req.skipSpace();
/*  673 */             modseq = req.parseInteger(req.readNumber(true));
/*  674 */             req.skipChar(')');
/*  675 */             req.skipSpace();
/*      */           }
/*      */           
/*  678 */           switch (req.peekChar()) {
/*      */           case 43: 
/*  680 */             req.skipChar('+');
/*  681 */             operation = StoreAction.ADD;
/*  682 */             break;
/*      */           case 45: 
/*  684 */             req.skipChar('-');
/*  685 */             operation = StoreAction.REMOVE;
/*      */           }
/*      */           
/*  688 */           String cmd = req.readATOM();
/*  689 */           if (cmd.equals("FLAGS.SILENT")) {
/*  690 */             silent = true;
/*  691 */           } else if (!cmd.equals("FLAGS")) {
/*  692 */             throw new ImapParseException(tag, "invalid store-att-flags");
/*      */           }
/*  694 */           req.skipSpace();
/*  695 */           List<String> flags = req.readFlags();
/*  696 */           checkEOF(tag, req);
/*  697 */           return isProxied ? this.imapProxy.proxy(req) : doSTORE(tag, sequence, flags, operation, silent, modseq, byUID); }
/*  698 */         if (command.equals("SELECT")) {
/*  699 */           byte params = 0;
/*  700 */           QResyncInfo qri = null;
/*  701 */           req.skipSpace();
/*  702 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*  703 */           if (req.peekChar() == 32) {
/*  704 */             req.skipSpace();req.skipChar('(');
/*  705 */             while (req.peekChar() != 41) {
/*  706 */               if (params != 0) {
/*  707 */                 req.skipSpace();
/*      */               }
/*  709 */               String param = req.readATOM();
/*  710 */               if ((param.equals("CONDSTORE")) && (extensionEnabled("CONDSTORE"))) {
/*  711 */                 params = (byte)(params | 0x2);
/*  712 */               } else if ((param.equals("QRESYNC")) && (sessionActivated(ImapExtension.QRESYNC))) {
/*  713 */                 params = (byte)(params | 0x2);
/*  714 */                 req.skipSpace();qri = parseQResyncInfo(req);
/*      */               } else {
/*  716 */                 throw new ImapParseException(tag, "unknown SELECT parameter \"" + param + '"');
/*      */               }
/*      */             }
/*  719 */             req.skipChar(')');
/*      */           }
/*  721 */           checkEOF(tag, req);
/*  722 */           return doSELECT(tag, path, params, qri); }
/*  723 */         if (command.equals("SEARCH")) {
/*  724 */           Integer options = null;
/*  725 */           req.skipSpace();
/*  726 */           if (("RETURN".equals(req.peekATOM())) && (extensionEnabled("ESEARCH"))) {
/*  727 */             options = Integer.valueOf(parseSearchOptions(req));
/*  728 */             req.skipSpace();
/*      */           }
/*  730 */           Charset charset = null;
/*  731 */           if ("CHARSET".equals(req.peekATOM())) {
/*  732 */             req.skipAtom("CHARSET");
/*  733 */             req.skipSpace();
/*  734 */             charset = req.readCharset();
/*  735 */             req.skipSpace();
/*      */           }
/*  737 */           ImapSearch i4search = req.readSearch(charset);
/*  738 */           checkEOF(tag, req);
/*  739 */           return isProxied ? this.imapProxy.proxy(req) : doSEARCH(tag, i4search, byUID, options); }
/*  740 */         if ((command.equals("STARTTLS")) && (extensionEnabled("STARTTLS"))) {
/*  741 */           checkEOF(tag, req);
/*  742 */           return doSTARTTLS(tag); }
/*  743 */         if (command.equals("STATUS")) {
/*  744 */           req.skipSpace();
/*  745 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*  746 */           req.skipSpace();
/*  747 */           byte status = parseStatusFields(req);
/*  748 */           checkEOF(tag, req);
/*  749 */           return doSTATUS(tag, path, status); }
/*  750 */         if ((command.equals("SORT")) && (extensionEnabled("SORT"))) {
/*  751 */           Integer options = null;
/*  752 */           req.skipSpace();
/*  753 */           if (("RETURN".equals(req.peekATOM())) && (extensionEnabled("ESORT"))) {
/*  754 */             options = Integer.valueOf(parseSearchOptions(req));req.skipSpace();
/*      */           }
/*  756 */           req.skipChar('(');
/*  757 */           boolean desc = false;
/*  758 */           List<SortBy> order = new ArrayList(2);
/*      */           do {
/*  760 */             if ((desc) || (!order.isEmpty())) {
/*  761 */               req.skipSpace();
/*      */             }
/*      */             
/*  764 */             String key = req.readATOM();
/*  765 */             if ((key.equals("REVERSE")) && (!desc)) {
/*  766 */               desc = true; } else { SortBy sort;
/*  767 */               if (key.equals("ARRIVAL")) {
/*  768 */                 sort = desc ? SortBy.DATE_DESC : SortBy.DATE_ASC; } else { SortBy sort;
/*  769 */                 if (key.equals("CC")) {
/*  770 */                   sort = SortBy.NONE; } else { SortBy sort;
/*  771 */                   if (key.equals("DATE")) {
/*  772 */                     sort = desc ? SortBy.DATE_DESC : SortBy.DATE_ASC; } else { SortBy sort;
/*  773 */                     if (key.equals("FROM")) {
/*  774 */                       sort = desc ? SortBy.NAME_DESC : SortBy.NAME_ASC; } else { SortBy sort;
/*  775 */                       if (key.equals("SIZE")) {
/*  776 */                         sort = desc ? SortBy.SIZE_DESC : SortBy.SIZE_ASC; } else { SortBy sort;
/*  777 */                         if (key.equals("SUBJECT")) {
/*  778 */                           sort = desc ? SortBy.SUBJ_DESC : SortBy.SUBJ_ASC; } else { SortBy sort;
/*  779 */                           if (key.equals("TO")) {
/*  780 */                             sort = desc ? SortBy.RCPT_DESC : SortBy.RCPT_ASC;
/*      */                           } else
/*  782 */                             throw new ImapParseException(tag, "unknown SORT key \"" + key + '"'); } } } } } }
/*      */               SortBy sort;
/*  784 */               order.add(sort);
/*  785 */               desc = false;
/*  786 */             } } while ((desc) || (req.peekChar() != 41));
/*  787 */           req.skipChar(')');
/*  788 */           req.skipSpace();
/*  789 */           Charset charset = req.readCharset();
/*  790 */           req.skipSpace();
/*  791 */           ImapSearch i4search = req.readSearch(charset);
/*  792 */           checkEOF(tag, req);
/*  793 */           return isProxied ? this.imapProxy.proxy(req) : doSORT(tag, i4search, byUID, options, order); }
/*  794 */         if (command.equals("SUBSCRIBE")) {
/*  795 */           req.skipSpace();ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*  796 */           checkEOF(tag, req);
/*  797 */           return doSUBSCRIBE(tag, path); }
/*  798 */         if ((command.equals("SETACL")) && (extensionEnabled("ACL"))) {
/*  799 */           StoreAction action = StoreAction.REPLACE;
/*  800 */           req.skipSpace();
/*  801 */           ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*  802 */           req.skipSpace();
/*  803 */           String principal = req.readAstring();
/*  804 */           req.skipSpace();
/*  805 */           String i4rights = req.readAstring();
/*  806 */           checkEOF(tag, req);
/*  807 */           if (i4rights.startsWith("+")) {
/*  808 */             action = StoreAction.ADD;
/*  809 */             i4rights = i4rights.substring(1);
/*  810 */           } else if (i4rights.startsWith("-")) {
/*  811 */             action = StoreAction.REMOVE;
/*  812 */             i4rights = i4rights.substring(1);
/*      */           }
/*  814 */           return doSETACL(tag, path, principal, i4rights, action); }
/*  815 */         if ((command.equals("SETQUOTA")) && (extensionEnabled("QUOTA"))) {
/*  816 */           Map<String, String> limits = new HashMap();
/*  817 */           req.skipSpace();
/*  818 */           req.readAstring();
/*  819 */           req.skipSpace();
/*  820 */           req.skipChar('(');
/*  821 */           while (req.peekChar() != 41) {
/*  822 */             if (!limits.isEmpty()) {
/*  823 */               req.skipSpace();
/*      */             }
/*  825 */             String resource = req.readATOM();
/*  826 */             req.skipSpace();
/*  827 */             limits.put(resource, req.readNumber());
/*      */           }
/*  829 */           req.skipChar(')');
/*  830 */           checkEOF(tag, req);
/*  831 */           return doSETQUOTA(tag);
/*      */         }
/*      */         break;
/*      */       case 'T': 
/*  835 */         if ((command.equals("THREAD")) && (extensionEnabled("THREAD=ORDEREDSUBJECT"))) {
/*  836 */           req.skipSpace();
/*  837 */           req.skipAtom("ORDEREDSUBJECT");
/*  838 */           req.skipSpace();
/*  839 */           Charset charset = req.readCharset();
/*  840 */           req.skipSpace();
/*  841 */           ImapSearch i4search = req.readSearch(charset);
/*  842 */           checkEOF(tag, req);
/*  843 */           return isProxied ? this.imapProxy.proxy(req) : doTHREAD(tag, i4search, byUID);
/*      */         }
/*      */         break;
/*      */       case 'U': 
/*  847 */         if (command.equals("UID")) {
/*  848 */           req.skipSpace();command = req.readATOM();
/*  849 */           if ((command.equals("FETCH")) || (command.equals("SEARCH")) || (command.equals("COPY")) || (command.equals("STORE")) || ((command.equals("EXPUNGE")) && (extensionEnabled("UIDPLUS"))) || ((command.equals("SORT")) && (extensionEnabled("SORT"))) || ((command.equals("THREAD")) && (extensionEnabled("THREAD=ORDEREDSUBJECT"))))
/*      */           {
/*      */ 
/*  852 */             byUID = true;
/*  853 */             this.lastCommand = (this.lastCommand + " " + command);
/*      */           }
/*      */           else {
/*  856 */             throw new ImapParseException(tag, "command not permitted with UID");
/*  857 */           } } else { if (command.equals("UNSUBSCRIBE")) {
/*  858 */             req.skipSpace();ImapPath path = new ImapPath(req.readFolder(), this.credentials);
/*  859 */             checkEOF(tag, req);
/*  860 */             return doUNSUBSCRIBE(tag, path); }
/*  861 */           if ((command.equals("UNSELECT")) && (extensionEnabled("UNSELECT"))) {
/*  862 */             checkEOF(tag, req);
/*  863 */             return doUNSELECT(tag);
/*      */           }
/*      */         }
/*      */         break;
/*  867 */       case 'X':  if (command.equals("XLIST")) {
/*  868 */           req.skipSpace();String base = req.readFolder();
/*  869 */           req.skipSpace();Set<String> patterns = Collections.singleton(req.readFolderPattern());
/*  870 */           checkEOF(tag, req);
/*  871 */           return doLIST(tag, base, patterns, (byte)0, (byte)4, (byte)0);
/*      */         }
/*      */         break;
/*      */       }
/*  875 */     } while (byUID);
/*      */     
/*  877 */     throw new ImapParseException(tag, "command not implemented");
/*      */   }
/*      */   
/*      */   private byte parseStatusFields(ImapRequest req) throws ImapParseException {
/*  881 */     byte status = 0;
/*  882 */     req.skipChar('(');
/*      */     do {
/*  884 */       if (status != 0) {
/*  885 */         req.skipSpace();
/*      */       }
/*  887 */       String flag = req.readATOM();
/*  888 */       if (flag.equals("MESSAGES")) {
/*  889 */         status = (byte)(status | 0x1);
/*  890 */       } else if (flag.equals("RECENT")) {
/*  891 */         status = (byte)(status | 0x2);
/*  892 */       } else if (flag.equals("UIDNEXT")) {
/*  893 */         status = (byte)(status | 0x4);
/*  894 */       } else if (flag.equals("UIDVALIDITY")) {
/*  895 */         status = (byte)(status | 0x8);
/*  896 */       } else if (flag.equals("UNSEEN")) {
/*  897 */         status = (byte)(status | 0x10);
/*  898 */       } else if (flag.equals("HIGHESTMODSEQ")) {
/*  899 */         status = (byte)(status | 0x20);
/*      */       } else {
/*  901 */         throw new ImapParseException(req.getTag(), "unknown STATUS attribute \"" + flag + '"');
/*      */       }
/*  903 */     } while (req.peekChar() != 41);
/*  904 */     req.skipChar(')');
/*  905 */     return status;
/*      */   }
/*      */   
/*      */   private int parseSearchOptions(ImapRequest req) throws ImapParseException {
/*  909 */     int options = 0;
/*  910 */     req.skipAtom("RETURN");
/*  911 */     req.skipSpace();
/*  912 */     req.skipChar('(');
/*  913 */     while (req.peekChar() != 41) {
/*  914 */       if (options != 0) {
/*  915 */         req.skipSpace();
/*      */       }
/*  917 */       String option = req.readATOM();
/*  918 */       if (option.equals("MIN")) {
/*  919 */         options |= 0x1;
/*  920 */       } else if (option.equals("MAX")) {
/*  921 */         options |= 0x2;
/*  922 */       } else if (option.equals("ALL")) {
/*  923 */         options |= 0x4;
/*  924 */       } else if (option.equals("COUNT")) {
/*  925 */         options |= 0x8;
/*  926 */       } else if ((option.equals("SAVE")) && (extensionEnabled("SEARCHRES"))) {
/*  927 */         options |= 0x10;
/*      */       } else {
/*  929 */         throw new ImapParseException(req.getTag(), "unknown RETURN option \"" + option + '"');
/*      */       }
/*      */     }
/*  932 */     req.skipChar(')');
/*  933 */     return options == 0 ? 4 : options;
/*      */   }
/*      */   
/*      */   private QResyncInfo parseQResyncInfo(ImapRequest req) throws ImapParseException {
/*  937 */     QResyncInfo qri = new QResyncInfo();
/*  938 */     req.skipChar('(');
/*  939 */     qri.uvv = req.parseInteger(req.readNumber());
/*  940 */     req.skipSpace();
/*  941 */     qri.modseq = req.parseInteger(req.readNumber());
/*  942 */     if (req.peekChar() == 32) {
/*  943 */       req.skipSpace();
/*  944 */       if (req.peekChar() != 40) {
/*  945 */         qri.knownUIDs = req.readSequence(false);
/*      */       }
/*  947 */       if ((qri.knownUIDs == null) || (req.peekChar() == 32)) {
/*  948 */         if (qri.knownUIDs != null) {
/*  949 */           req.skipSpace();
/*      */         }
/*  951 */         req.skipChar('(');
/*  952 */         qri.seqMilestones = req.readSequence(false);
/*  953 */         req.skipSpace();
/*  954 */         qri.uidMilestones = req.readSequence(false);
/*  955 */         req.skipChar(')');
/*      */       }
/*      */     }
/*  958 */     req.skipChar(')');
/*  959 */     return qri;
/*      */   }
/*      */   
/*      */   State getState() {
/*  963 */     if (this.goodbyeSent)
/*  964 */       return State.LOGOUT;
/*  965 */     if ((this.selectedFolder != null) || (this.imapProxy != null))
/*  966 */       return State.SELECTED;
/*  967 */     if (isAuthenticated()) {
/*  968 */       return State.AUTHENTICATED;
/*      */     }
/*  970 */     return State.NOT_AUTHENTICATED;
/*      */   }
/*      */   
/*      */   protected boolean isAuthenticated()
/*      */   {
/*  975 */     return this.credentials != null;
/*      */   }
/*      */   
/*      */   boolean checkState(String tag, State required) throws IOException {
/*  979 */     State state = getState();
/*  980 */     if ((required == State.NOT_AUTHENTICATED) && (state != State.NOT_AUTHENTICATED)) {
/*  981 */       sendNO(tag, "must be in NOT AUTHENTICATED state");
/*  982 */       return false; }
/*  983 */     if ((required == State.AUTHENTICATED) && ((state == State.NOT_AUTHENTICATED) || (state == State.LOGOUT))) {
/*  984 */       sendNO(tag, "must be in AUTHENTICATED or SELECTED state");
/*  985 */       return false; }
/*  986 */     if ((required == State.SELECTED) && (state != State.SELECTED)) {
/*  987 */       sendNO(tag, "must be in SELECTED state");
/*  988 */       return false;
/*      */     }
/*  990 */     return true;
/*      */   }
/*      */   
/*      */   ImapSession getCurrentSession()
/*      */   {
/*  995 */     return getState() == State.LOGOUT ? null : this.selectedFolder;
/*      */   }
/*      */   
/*      */   ImapFolder getSelectedFolder() throws ImapSessionClosedException {
/*  999 */     ImapSession i4selected = getCurrentSession();
/* 1000 */     return i4selected == null ? null : i4selected.getImapFolder();
/*      */   }
/*      */   
/*      */   void unsetSelectedFolder(boolean sendClosed) throws IOException {
/* 1004 */     ImapSession i4selected = this.selectedFolder;
/* 1005 */     this.selectedFolder = null;
/* 1006 */     if (i4selected != null) {
/* 1007 */       ImapSessionManager.getInstance().closeFolder(i4selected, false);
/* 1008 */       if ((sendClosed) && (sessionActivated(ImapExtension.QRESYNC))) {
/* 1009 */         sendUntagged("OK [CLOSED] mailbox closed");
/*      */       }
/*      */     }
/*      */     
/* 1013 */     ImapProxy proxy = this.imapProxy;
/* 1014 */     this.imapProxy = null;
/* 1015 */     if (proxy != null) {
/* 1016 */       proxy.dropConnection();
/* 1017 */       if ((sendClosed) && (sessionActivated(ImapExtension.QRESYNC))) {
/* 1018 */         sendUntagged("OK [CLOSED] mailbox closed");
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   Pair<ImapSession, ImapSessionManager.InitialFolderValues> setSelectedFolder(ImapPath path, byte params) throws ServiceException, IOException {
/* 1024 */     unsetSelectedFolder(true);
/* 1025 */     if (path == null) {
/* 1026 */       return new Pair(null, null);
/*      */     }
/* 1028 */     Pair<ImapSession, ImapSessionManager.InitialFolderValues> selectdata = ImapSessionManager.getInstance().openFolder(path, params, this);
/* 1029 */     this.selectedFolder = ((ImapSession)selectdata.getFirst());
/*      */     
/* 1031 */     ZimbraLog.imap.info("selected folder " + ((ImapSession)selectdata.getFirst()).getPath());
/* 1032 */     return selectdata;
/*      */   }
/*      */   
/*      */   boolean canContinue(ServiceException e) {
/* 1036 */     return !e.getCode().equals("mail.MAINTENANCE");
/*      */   }
/*      */   
/*      */   OperationContext getContext() throws ServiceException {
/* 1040 */     if (!isAuthenticated()) {
/* 1041 */       throw ServiceException.AUTH_REQUIRED();
/*      */     }
/* 1043 */     return this.credentials.getContext().setSession(this.selectedFolder);
/*      */   }
/*      */   
/*      */   boolean doCAPABILITY(String tag) throws IOException
/*      */   {
/* 1048 */     sendUntagged(getCapabilityString());
/* 1049 */     sendOK(tag, "CAPABILITY completed");
/* 1050 */     return true;
/*      */   }
/*      */   
/* 1053 */   private static final Set<String> SUPPORTED_EXTENSIONS = new LinkedHashSet(Arrays.asList(new String[] { "ACL", "BINARY", "CATENATE", "CHILDREN", "CONDSTORE", "ENABLE", "ESEARCH", "ESORT", "I18NLEVEL=1", "ID", "IDLE", "LIST-EXTENDED", "LIST-STATUS", "LITERAL+", "LOGIN-REFERRALS", "MULTIAPPEND", "NAMESPACE", "QRESYNC", "QUOTA", "RIGHTS=ektx", "SASL-IR", "SEARCHRES", "SORT", "THREAD=ORDEREDSUBJECT", "UIDPLUS", "UNSELECT", "WITHIN", "XLIST" }));
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private static final byte SELECT_SUBSCRIBED = 1;
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private static final byte SELECT_REMOTE = 2;
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private static final byte SELECT_RECURSIVE = 4;
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   private static final byte RETURN_SUBSCRIBED = 1;
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   private static final byte RETURN_CHILDREN = 2;
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   private static final byte RETURN_XLIST = 4;
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   protected String getCapabilityString()
/*      */   {
/* 1094 */     StringBuilder capability = new StringBuilder("CAPABILITY IMAP4rev1");
/*      */     AuthenticatorUser authUser;
/* 1096 */     if (!isAuthenticated()) {
/* 1097 */       if ((!this.startedTLS) && (!this.config.isCleartextLoginEnabled())) {
/* 1098 */         capability.append(" LOGINDISABLED");
/*      */       }
/* 1100 */       if ((!this.startedTLS) && (extensionEnabled("STARTTLS"))) {
/* 1101 */         capability.append(" STARTTLS");
/*      */       }
/* 1103 */       authUser = new ImapAuthenticatorUser(this, null);
/* 1104 */       for (String mechanism : Authenticator.listMechanisms()) {
/* 1105 */         if ((mechanismEnabled(mechanism)) && (Authenticator.getAuthenticator(mechanism, authUser) != null) && (!mechanism.equalsIgnoreCase("X-ZIMBRA")))
/*      */         {
/* 1107 */           capability.append(" AUTH=").append(mechanism);
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 1112 */     for (String extension : SUPPORTED_EXTENSIONS) {
/* 1113 */       if (extensionEnabled(extension)) {
/* 1114 */         capability.append(' ').append(extension);
/*      */       }
/*      */     }
/*      */     
/* 1118 */     return capability.toString();
/*      */   }
/*      */   
/*      */   boolean extensionEnabled(String extension) {
/* 1122 */     if (this.config.isCapabilityDisabled(extension))
/*      */     {
/* 1124 */       return false; }
/* 1125 */     if (extension.equalsIgnoreCase("SEARCHRES"))
/*      */     {
/* 1127 */       return extensionEnabled("ESEARCH"); }
/* 1128 */     if (extension.equalsIgnoreCase("RIGHTS=ektx"))
/* 1129 */       return extensionEnabled("ACL");
/* 1130 */     if (extension.equalsIgnoreCase("QRESYNC"))
/* 1131 */       return extensionEnabled("CONDSTORE");
/* 1132 */     if (extension.equalsIgnoreCase("ESORT"))
/* 1133 */       return extensionEnabled("SORT");
/* 1134 */     if (extension.equalsIgnoreCase("LIST-STATUS"))
/* 1135 */       return extensionEnabled("LIST-EXTENDED");
/* 1136 */     if ((extension.equalsIgnoreCase("IDLE")) && (this.credentials != null) && (this.credentials.isHackEnabled(ImapCredentials.EnabledHack.NO_IDLE)))
/*      */     {
/*      */ 
/* 1139 */       return false;
/*      */     }
/* 1141 */     return true;
/*      */   }
/*      */   
/*      */   private boolean mechanismEnabled(String mechanism)
/*      */   {
/* 1146 */     return extensionEnabled("AUTH=" + mechanism);
/*      */   }
/*      */   
/*      */   boolean doNOOP(String tag) throws IOException {
/* 1150 */     sendNotifications(true, false);
/* 1151 */     sendOK(tag, "NOOP completed");
/* 1152 */     return true;
/*      */   }
/*      */   
/*      */ 
/*      */   boolean doID(String tag, Map<String, String> fields)
/*      */     throws IOException
/*      */   {
/* 1159 */     setIDFields(fields);
/* 1160 */     sendNotifications(true, false);
/* 1161 */     if (isAuthenticated()) {
/* 1162 */       String localServerId = null;
/*      */       try {
/* 1164 */         localServerId = Provisioning.getInstance().getLocalServer().getId();
/*      */       } catch (ServiceException e) {
/* 1166 */         ZimbraLog.imap.warn("Error in getting local server id", e);
/*      */       }
/* 1168 */       sendUntagged("ID (" + ID_PARAMS + " \"USER\" \"" + this.credentials.getUsername() + (localServerId == null ? "" : new StringBuilder().append("\" \"SERVER\" \"").append(localServerId).toString()) + "\")");
/*      */     }
/*      */     else {
/* 1171 */       sendUntagged("ID (" + ID_PARAMS + ")");
/*      */     }
/* 1173 */     sendOK(tag, "ID completed");
/* 1174 */     return true;
/*      */   }
/*      */   
/*      */   private void setIDFields(Map<String, String> paramFields) {
/* 1178 */     if (paramFields == null) {
/* 1179 */       return;
/*      */     }
/*      */     
/* 1182 */     Map<String, String> fields = new TreeMap(String.CASE_INSENSITIVE_ORDER);
/* 1183 */     fields.putAll(paramFields);
/* 1184 */     String ip = (String)fields.get("X-ORIGINATING-IP");
/* 1185 */     if (ip != null) {
/* 1186 */       if (this.origRemoteIp == null) {
/* 1187 */         this.origRemoteIp = ip;
/* 1188 */         ZimbraLog.addOrigIpToContext(ip);
/*      */       }
/* 1190 */       else if (this.origRemoteIp.equals(ip)) {
/* 1191 */         ZimbraLog.imap.warn("IMAP ID with %s is allowed only once per session, command ignored", new Object[] { "X-ORIGINATING-IP" });
/*      */       }
/*      */       else {
/* 1194 */         ZimbraLog.imap.error("IMAP ID with %s is allowed only once per session, received different IP: %s, command ignored", new Object[] { "X-ORIGINATING-IP", ip });
/*      */       }
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 1200 */     String xvia = (String)fields.get("X-VIA");
/* 1201 */     if (xvia != null) {
/* 1202 */       if (this.via == null) {
/* 1203 */         this.via = xvia;
/* 1204 */         ZimbraLog.addViaToContext(this.via);
/*      */       }
/* 1206 */       else if (this.via.equals(xvia)) {
/* 1207 */         ZimbraLog.imap.warn("IMAP ID with %s is allowed only once per session, command ignored", new Object[] { "X-VIA" });
/*      */       } else {
/* 1209 */         ZimbraLog.imap.error("IMAP ID with %s is allowed only once per session, received different value: %s, command ignored", new Object[] { "X-VIA", xvia });
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 1214 */     String ua = (String)fields.get("name");
/* 1215 */     if (ua != null) {
/* 1216 */       String version = (String)fields.get("version");
/* 1217 */       if (version != null) {
/* 1218 */         ua = ua + '/' + version;
/*      */       }
/* 1220 */       if (this.userAgent == null) {
/* 1221 */         this.userAgent = ua;
/* 1222 */         ZimbraLog.addUserAgentToContext(ua);
/* 1223 */       } else if (this.userAgent.equals(ua)) {
/* 1224 */         ZimbraLog.imap.warn("IMAP ID with %s/%s provided duplicate values, command ignored", new Object[] { "name", "version" });
/*      */       } else {
/* 1226 */         ZimbraLog.imap.debug("IMAP ID with %s/%s superceeds old UA [%s] with new UA [%s]", new Object[] { "name", "version", this.userAgent, ua });
/* 1227 */         this.userAgent = ua;
/* 1228 */         ZimbraLog.addUserAgentToContext(ua);
/*      */       }
/*      */     }
/*      */     
/* 1232 */     ZimbraLog.imap.debug("IMAP client identified as: %s", new Object[] { fields });
/*      */   }
/*      */   
/*      */   String getNextVia() {
/* 1236 */     StringBuilder result = new StringBuilder();
/* 1237 */     if (this.via != null) {
/* 1238 */       result.append(this.via).append(',');
/*      */     }
/* 1240 */     result.append(this.origRemoteIp != null ? this.origRemoteIp : getRemoteIp());
/* 1241 */     if (this.userAgent != null) {
/* 1242 */       result.append('(').append(this.userAgent).append(')');
/*      */     }
/* 1244 */     return result.toString();
/*      */   }
/*      */   
/*      */   boolean doENABLE(String tag, List<String> extensions) throws IOException {
/* 1248 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 1249 */       return true;
/*      */     }
/* 1251 */     StringBuilder enabled = new StringBuilder("ENABLED");
/*      */     
/* 1253 */     List<ImapExtension> targets = new ArrayList(extensions.size());
/* 1254 */     for (String ext : extensions)
/*      */     {
/*      */ 
/* 1257 */       if ((SUPPORTED_EXTENSIONS.contains(ext)) && (extensionEnabled(ext)))
/*      */       {
/*      */ 
/* 1260 */         if (ext.equals("CONDSTORE")) {
/* 1261 */           targets.add(ImapExtension.CONDSTORE);
/* 1262 */         } else { if (!ext.equals("QRESYNC")) continue;
/* 1263 */           targets.add(ImapExtension.CONDSTORE);
/* 1264 */           targets.add(ImapExtension.QRESYNC);
/*      */         }
/*      */         
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 1272 */         enabled.append(' ').append(ext);
/*      */       }
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 1278 */     for (ImapExtension i4x : targets) {
/* 1279 */       activateExtension(i4x);
/*      */     }
/* 1281 */     sendUntagged(enabled.toString());
/* 1282 */     sendNotifications(true, false);
/* 1283 */     sendOK(tag, "ENABLE completed");
/* 1284 */     return true;
/*      */   }
/*      */   
/*      */   void activateExtension(ImapExtension ext) {
/* 1288 */     if (ext == null) {
/* 1289 */       return;
/*      */     }
/* 1291 */     if (this.activeExtensions == null) {
/* 1292 */       this.activeExtensions = new HashSet(1);
/*      */     }
/* 1294 */     this.activeExtensions.add(ext);
/*      */   }
/*      */   
/*      */   boolean sessionActivated(ImapExtension ext) {
/* 1298 */     return (this.activeExtensions != null) && (this.activeExtensions.contains(ext));
/*      */   }
/*      */   
/*      */   boolean doLOGOUT(String tag) throws IOException {
/* 1302 */     sendBYE();
/* 1303 */     if (this.credentials != null) {
/* 1304 */       ZimbraLog.imap.info("dropping connection for user " + this.credentials.getUsername() + " (LOGOUT)");
/*      */     }
/* 1306 */     sendOK(tag, "LOGOUT completed");
/* 1307 */     return false;
/*      */   }
/*      */   
/*      */   boolean doAUTHENTICATE(String tag, String mechanism, byte[] initial) throws IOException {
/* 1311 */     if (!checkState(tag, State.NOT_AUTHENTICATED)) {
/* 1312 */       return true;
/*      */     }
/* 1314 */     AuthenticatorUser authUser = new ImapAuthenticatorUser(this, tag);
/* 1315 */     Authenticator auth = Authenticator.getAuthenticator(mechanism, authUser);
/*      */     
/*      */ 
/* 1318 */     if ((auth == null) || (!mechanismEnabled(mechanism))) {
/* 1319 */       sendNO(tag, "mechanism not supported: " + mechanism);
/* 1320 */       return true;
/*      */     }
/*      */     
/* 1323 */     this.authenticator = auth;
/* 1324 */     this.authenticator.setLocalAddress(getLocalAddress().getAddress());
/* 1325 */     if (!this.authenticator.initialize()) {
/* 1326 */       this.authenticator = null;
/* 1327 */       return true;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 1334 */     if (initial != null) {
/* 1335 */       return continueAuthentication(initial);
/*      */     }
/* 1337 */     sendContinuation("");
/* 1338 */     return true;
/*      */   }
/*      */   
/*      */   boolean doLOGIN(String tag, String username, String password) throws IOException {
/* 1342 */     if (!checkState(tag, State.NOT_AUTHENTICATED)) {
/* 1343 */       return true;
/*      */     }
/* 1345 */     if ((!this.startedTLS) && (!this.config.isCleartextLoginEnabled())) {
/* 1346 */       sendNO(tag, "cleartext logins disabled");
/* 1347 */       return true;
/*      */     }
/*      */     
/* 1350 */     boolean cont = authenticate(username, null, password, tag, null);
/* 1351 */     if (isAuthenticated())
/*      */     {
/*      */ 
/*      */ 
/* 1355 */       sendOK(tag, '[' + getCapabilityString() + "] LOGIN completed");
/* 1356 */       enableInactivityTimer();
/*      */     }
/* 1358 */     return cont;
/*      */   }
/*      */   
/*      */   boolean authenticate(String username, String authenticateId, String password, String tag, Authenticator auth)
/*      */     throws IOException
/*      */   {
/* 1364 */     ImapCredentials.EnabledHack enabledHack = ImapCredentials.EnabledHack.NONE;
/* 1365 */     if ((username != null) && (username.length() != 0)) {
/* 1366 */       for (ImapCredentials.EnabledHack hack : ImapCredentials.EnabledHack.values()) {
/* 1367 */         if ((hack.toString() != null) && (username.endsWith(hack.toString()))) {
/* 1368 */           enabledHack = hack;
/* 1369 */           username = username.substring(0, username.length() - hack.toString().length());
/* 1370 */           break;
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 1375 */     String mechanism = auth != null ? auth.getMechanism() : null;
/* 1376 */     String command = auth != null ? "AUTHENTICATE" : "LOGIN";
/*      */     
/*      */ 
/* 1379 */     if (auth == null) {
/* 1380 */       auth = new PlainAuthenticator(new ImapAuthenticatorUser(this, tag));
/* 1381 */       authenticateId = username;
/*      */     }
/*      */     
/*      */ 
/*      */     try
/*      */     {
/* 1387 */       Account acct = auth.authenticate(username, authenticateId, password, AuthContext.Protocol.imap, this.origRemoteIp, getRemoteIp(), this.userAgent);
/*      */       
/* 1389 */       if (acct == null)
/*      */       {
/* 1391 */         sendNO(tag, command + " failed");
/* 1392 */         return true;
/*      */       }
/*      */       
/*      */ 
/* 1396 */       startSession(acct, enabledHack, tag, mechanism);
/*      */     }
/*      */     catch (AccountServiceException.AuthFailedServiceException afe) {
/* 1399 */       setCredentials(null);
/*      */       
/* 1401 */       ZimbraLog.imap.info(afe.getMessage() + " (" + afe.getReason() + ')');
/* 1402 */       sendNO(tag, command + " failed");
/* 1403 */       return true;
/*      */     } catch (ServiceException e) {
/* 1405 */       setCredentials(null);
/*      */       
/* 1407 */       ZimbraLog.imap.warn(command + " failed", e);
/* 1408 */       if (e.getCode().equals("account.CHANGE_PASSWORD")) {
/* 1409 */         sendNO(tag, "[ALERT] password must be changed before IMAP login permitted");
/* 1410 */       } else if (e.getCode().equals("account.MAINTENANCE_MODE")) {
/* 1411 */         sendNO(tag, "[ALERT] account undergoing maintenance; please try again later");
/*      */       } else {
/* 1413 */         sendNO(tag, command + " failed");
/*      */       }
/* 1415 */       return canContinue(e);
/*      */     }
/*      */     
/* 1418 */     return true;
/*      */   }
/*      */   
/*      */   private ImapCredentials startSession(Account account, ImapCredentials.EnabledHack hack, String tag, String mechanism) throws ServiceException, IOException
/*      */   {
/* 1423 */     String command = mechanism != null ? "AUTHENTICATE" : "LOGIN";
/*      */     
/* 1425 */     if (!account.getBooleanAttr("zimbraImapEnabled", false)) {
/* 1426 */       sendNO(tag, "account does not have IMAP access enabled");
/* 1427 */       return null; }
/* 1428 */     if ((!"X-ZIMBRA".equals(mechanism)) && (!Provisioning.onLocalServer(account))) {
/* 1429 */       String correctHost = account.getMailHost();
/* 1430 */       ZimbraLog.imap.info(command + " failed; should be on host " + correctHost);
/* 1431 */       if ((correctHost == null) || (correctHost.trim().equals("")) || (!extensionEnabled("LOGIN_REFERRALS"))) {
/* 1432 */         sendNO(tag, command + " failed (wrong host)");
/*      */       } else {
/* 1434 */         sendNO(tag, "[REFERRAL imap://" + URLEncoder.encode(account.getName(), "utf-8") + '@' + correctHost + "/] " + command + " failed");
/*      */       }
/*      */       
/* 1437 */       return null;
/*      */     }
/*      */     
/* 1440 */     setCredentials(new ImapCredentials(account, hack));
/* 1441 */     if (this.credentials.isLocal()) {
/* 1442 */       this.credentials.getMailbox().beginTrackingImap();
/*      */     }
/* 1444 */     ZimbraLog.addAccountNameToContext(this.credentials.getUsername());
/* 1445 */     ZimbraLog.imap.info("user %s authenticated, mechanism=%s%s", new Object[] { this.credentials.getUsername(), mechanism == null ? "LOGIN" : mechanism, this.startedTLS ? " [TLS]" : "" });
/*      */     
/*      */ 
/* 1448 */     return this.credentials;
/*      */   }
/*      */   
/*      */   boolean doSELECT(String tag, ImapPath path, byte params, QResyncInfo qri) throws IOException, ImapException {
/* 1452 */     checkCommandThrottle(new SelectCommand(path, params, qri));
/* 1453 */     return selectFolder(tag, "SELECT", path, params, qri);
/*      */   }
/*      */   
/*      */   boolean doEXAMINE(String tag, ImapPath path, byte params, QResyncInfo qri) throws IOException, ImapException {
/* 1457 */     checkCommandThrottle(new ExamineCommand(path, params, qri));
/* 1458 */     return selectFolder(tag, "EXAMINE", path, (byte)(params | 0x1), qri);
/*      */   }
/*      */   
/*      */   private boolean selectFolder(String tag, String command, ImapPath path, byte params, QResyncInfo qri) throws IOException, ImapException
/*      */   {
/* 1463 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 1464 */       return true;
/*      */     }
/* 1466 */     ImapFolder i4folder = null;
/* 1467 */     ImapSessionManager.InitialFolderValues initial = null;
/*      */     
/* 1469 */     List<String> permflags = Collections.emptyList();
/*      */     boolean writable;
/*      */     try {
/* 1472 */       Object mboxobj = (DebugConfig.imapProxyToLocalhost) && (path.useReferent()) ? path.getOwnerZMailbox() : path.getOwnerMailbox();
/*      */       
/* 1474 */       if ((mboxobj instanceof ZMailbox))
/*      */       {
/*      */ 
/*      */ 
/* 1478 */         unsetSelectedFolder(true);
/*      */         
/* 1480 */         ImapProxy proxy = new ImapProxy(this, path);
/* 1481 */         if (proxy.select(tag, params, qri)) {
/* 1482 */           this.imapProxy = proxy;
/*      */         } else {
/* 1484 */           proxy.dropConnection();
/*      */         }
/* 1486 */         return true;
/*      */       }
/*      */       
/* 1489 */       Pair<ImapSession, ImapSessionManager.InitialFolderValues> selectdata = setSelectedFolder(path, params);
/* 1490 */       i4folder = ((ImapSession)selectdata.getFirst()).getImapFolder();
/* 1491 */       initial = (ImapSessionManager.InitialFolderValues)selectdata.getSecond();
/*      */       
/* 1493 */       writable = i4folder.isWritable();
/* 1494 */       if (writable)
/*      */       {
/*      */ 
/* 1497 */         permflags = i4folder.getFlagList(true);
/* 1498 */         if (!path.isWritable((short)8)) {
/* 1499 */           permflags.remove("\\Deleted");
/*      */         }
/* 1501 */         if (path.belongsTo(this.credentials)) {
/* 1502 */           permflags.add("\\*");
/*      */         }
/*      */         
/*      */       }
/*      */     }
/*      */     catch (ServiceException e)
/*      */     {
/* 1509 */       unsetSelectedFolder(true);
/*      */       
/* 1511 */       if (e.getCode().equals("mail.NO_SUCH_FOLDER")) {
/* 1512 */         ZimbraLog.imap.info("%s failed: no such folder: %s", new Object[] { command, path });
/* 1513 */       } else if (e.getCode().equals("service.PERM_DENIED")) {
/* 1514 */         ZimbraLog.imap.info("%s failed: permission denied: %s", new Object[] { command, path });
/* 1515 */       } else if (e.getCode().equals("account.NO_SUCH_ACCOUNT")) {
/* 1516 */         ZimbraLog.imap.info("%s failed: no such account: %s", new Object[] { command, path });
/*      */       } else {
/* 1518 */         ZimbraLog.imap.warn("%s failed", command, e);
/*      */       }
/* 1520 */       sendNO(tag, command + " failed");
/* 1521 */       return canContinue(e);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/* 1527 */     sendUntagged(i4folder.getSize() + " EXISTS");
/* 1528 */     sendUntagged(i4folder.getRecentCount() + " RECENT");
/* 1529 */     if (initial.firstUnread > 0) {
/* 1530 */       sendUntagged("OK [UNSEEN " + initial.firstUnread + "] mailbox contains unseen messages");
/*      */     }
/* 1532 */     sendUntagged("OK [UIDVALIDITY " + i4folder.getUIDValidity() + "] UIDs are valid for this mailbox");
/* 1533 */     if (!i4folder.isVirtual()) {
/* 1534 */       sendUntagged("OK [UIDNEXT " + initial.uidnext + "] next expected UID is " + initial.uidnext);
/*      */     }
/* 1536 */     sendUntagged("FLAGS (" + StringUtil.join(" ", i4folder.getFlagList(false)) + ')');
/* 1537 */     sendUntagged("OK [PERMANENTFLAGS (" + StringUtil.join(" ", permflags) + ")] junk-related flags are not permanent");
/* 1538 */     if (!i4folder.isVirtual()) {
/* 1539 */       sendUntagged("OK [HIGHESTMODSEQ " + initial.modseq + "] modseq tracked on this mailbox");
/*      */     } else {
/* 1541 */       sendUntagged("OK [NOMODSEQ] modseq not supported on search folders");
/*      */     }
/*      */     
/* 1544 */     if ((qri != null) && (qri.uvv == i4folder.getUIDValidity()) && (!i4folder.isVirtual())) {
/* 1545 */       boolean sentVanished = false;
/* 1546 */       String knownUIDs = qri.knownUIDs == null ? "1:" + (initial.uidnext - 1) : qri.knownUIDs;
/* 1547 */       if ((qri.seqMilestones != null) && (qri.uidMilestones != null)) {
/* 1548 */         int lowwater = i4folder.getSequenceMatchDataLowWater(tag, qri.seqMilestones, qri.uidMilestones);
/* 1549 */         if (lowwater > 1) {
/* 1550 */           String constrainedSet = i4folder.cropSubsequence(knownUIDs, true, lowwater, -1);
/* 1551 */           String vanished = i4folder.invertSubsequence(constrainedSet, true, i4folder.getAllMessages());
/* 1552 */           if (!vanished.isEmpty()) {
/* 1553 */             sendUntagged("VANISHED (EARLIER) " + vanished);
/*      */           }
/* 1555 */           sentVanished = true;
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 1565 */       fetch(tag, knownUIDs, 0x8 | (sentVanished ? '\000' : 'Ȁ'), null, true, qri.modseq, false, true);
/*      */     }
/*      */     
/*      */ 
/* 1569 */     sendOK(tag, (writable ? "[READ-WRITE] " : "[READ-ONLY] ") + command + " completed");
/* 1570 */     return true;
/*      */   }
/*      */   
/*      */   boolean doCREATE(String tag, ImapPath path) throws IOException, ImapThrottledException {
/* 1574 */     checkCommandThrottle(new CreateCommand(path));
/* 1575 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 1576 */       return true;
/*      */     }
/* 1578 */     if (!path.isCreatable()) {
/* 1579 */       ZimbraLog.imap.info("CREATE failed: hidden folder or parent: " + path);
/* 1580 */       sendNO(tag, "CREATE failed");
/* 1581 */       return true;
/*      */     }
/*      */     try
/*      */     {
/* 1585 */       Object mboxobj = path.getOwnerMailbox();
/* 1586 */       if ((mboxobj instanceof Mailbox)) {
/* 1587 */         ((Mailbox)mboxobj).createFolder(getContext(), path.asResolvedPath(), new Folder.FolderOptions().setDefaultView(MailItem.Type.MESSAGE));
/* 1588 */       } else if ((mboxobj instanceof ZMailbox)) {
/* 1589 */         ((ZMailbox)mboxobj).createFolder(null, path.asResolvedPath(), ZFolder.View.message, ZFolder.Color.DEFAULTCOLOR, null, null);
/*      */       } else {
/* 1591 */         throw AccountServiceException.NO_SUCH_ACCOUNT(path.getOwner());
/*      */       }
/*      */     } catch (ServiceException e) {
/* 1594 */       String cause = "CREATE failed";
/* 1595 */       if (e.getCode().equals("mail.CANNOT_CONTAIN")) {
/* 1596 */         cause = cause + ": superior mailbox has \\Noinferiors set";
/* 1597 */       } else if (e.getCode().equals("mail.ALREADY_EXISTS")) {
/* 1598 */         cause = cause + ": mailbox already exists";
/* 1599 */       } else if (e.getCode().equals("mail.INVALID_NAME")) {
/* 1600 */         cause = cause + ": invalid mailbox name";
/* 1601 */       } else if (e.getCode().equals("service.PERM_DENIED")) {
/* 1602 */         cause = cause + ": permission denied";
/*      */       }
/* 1604 */       if (cause.equals("CREATE failed")) {
/* 1605 */         ZimbraLog.imap.warn(cause, e);
/*      */       } else {
/* 1607 */         ZimbraLog.imap.info("%s: %s", new Object[] { cause, path });
/*      */       }
/* 1609 */       sendNO(tag, cause);
/* 1610 */       return canContinue(e);
/*      */     }
/*      */     
/* 1613 */     sendNotifications(true, false);
/* 1614 */     sendOK(tag, "CREATE completed");
/* 1615 */     return true;
/*      */   }
/*      */   
/*      */   boolean doDELETE(String tag, ImapPath path) throws IOException {
/* 1619 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 1620 */       return true;
/*      */     }
/*      */     try {
/* 1623 */       if (!path.isVisible()) {
/* 1624 */         throw ImapServiceException.FOLDER_NOT_VISIBLE(path.asImapPath());
/*      */       }
/*      */       
/* 1627 */       if (getState() == State.SELECTED) {
/* 1628 */         ImapSession i4selected = getCurrentSession();
/* 1629 */         if ((i4selected != null) && (path.isEquivalent(i4selected.getPath()))) {
/* 1630 */           unsetSelectedFolder(true);
/* 1631 */         } else if ((this.imapProxy != null) && (path.isEquivalent(this.imapProxy.getPath()))) {
/* 1632 */           unsetSelectedFolder(true);
/*      */         }
/*      */       }
/*      */       
/* 1636 */       Object mboxobj = path.getOwnerMailbox();
/* 1637 */       if (path.useReferent())
/*      */       {
/*      */ 
/* 1640 */         this.credentials.hideFolder(path);
/*      */         
/* 1642 */         this.credentials.unsubscribe(path);
/* 1643 */       } else if ((mboxobj instanceof Mailbox)) {
/* 1644 */         Mailbox mbox = (Mailbox)mboxobj;
/* 1645 */         Folder folder = (Folder)path.getFolder();
/* 1646 */         if (!folder.isDeletable()) {
/* 1647 */           throw ImapServiceException.CANNOT_DELETE_SYSTEM_FOLDER(folder.getPath());
/*      */         }
/* 1649 */         if (!folder.hasSubfolders()) {
/* 1650 */           mbox.delete(getContext(), folder.getId(), MailItem.Type.FOLDER);
/*      */           
/* 1652 */           this.credentials.unsubscribe(path);
/*      */ 
/*      */         }
/*      */         else
/*      */         {
/*      */ 
/* 1658 */           mbox.emptyFolder(getContext(), folder.getId(), false);
/*      */         }
/*      */       }
/* 1661 */       else if ((mboxobj instanceof ZMailbox)) {
/* 1662 */         ZMailbox zmbx = (ZMailbox)mboxobj;
/* 1663 */         ZFolder zfolder = (ZFolder)path.getFolder();
/*      */         
/* 1665 */         if (zfolder.getSubFolders().isEmpty()) {
/* 1666 */           zmbx.deleteFolder(zfolder.getId());
/*      */           
/* 1668 */           this.credentials.unsubscribe(path);
/*      */         } else {
/* 1670 */           zmbx.emptyFolder(zfolder.getId(), false);
/*      */         }
/*      */       } else {
/* 1673 */         throw AccountServiceException.NO_SUCH_ACCOUNT(path.getOwner());
/*      */       }
/*      */     } catch (ServiceException e) {
/* 1676 */       if (e.getCode().equals("mail.NO_SUCH_FOLDER")) {
/* 1677 */         ZimbraLog.imap.info("DELETE failed: no such folder: %s", new Object[] { path });
/* 1678 */       } else if (e.getCode().equals("account.NO_SUCH_ACCOUNT")) {
/* 1679 */         ZimbraLog.imap.info("DELETE failed: no such account: %s", new Object[] { path });
/* 1680 */       } else if (e.getCode().equals("imap.FOLDER_NOT_VISIBLE")) {
/* 1681 */         ZimbraLog.imap.info("DELETE failed: folder not visible: %s", new Object[] { path });
/* 1682 */       } else if (e.getCode().equals("imap.CANNOT_DELETE_SYSTEM_FOLDER")) {
/* 1683 */         ZimbraLog.imap.info("DELETE failed: system folder cannot be deleted: %s", new Object[] { path });
/* 1684 */       } else if (e.getCode().equals("service.PERM_DENIED")) {
/* 1685 */         ZimbraLog.imap.info("DELETE failed: permission denied: %s", new Object[] { path });
/*      */       } else {
/* 1687 */         ZimbraLog.imap.warn("DELETE failed", e);
/*      */       }
/* 1689 */       sendNO(tag, "DELETE failed");
/* 1690 */       return canContinue(e);
/*      */     }
/*      */     
/* 1693 */     sendNotifications(true, false);
/* 1694 */     sendOK(tag, "DELETE completed");
/* 1695 */     return true;
/*      */   }
/*      */   
/*      */   boolean doRENAME(String tag, ImapPath oldPath, ImapPath newPath) throws IOException {
/* 1699 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 1700 */       return true;
/*      */     }
/*      */     try {
/* 1703 */       Account source = oldPath.getOwnerAccount();Account target = newPath.getOwnerAccount();
/* 1704 */       if ((source == null) || (target == null)) {
/* 1705 */         ZimbraLog.imap.info("RENAME failed: no such account for %s or %s", new Object[] { oldPath, newPath });
/* 1706 */         sendNO(tag, "RENAME failed: no such account");
/* 1707 */         return true; }
/* 1708 */       if (!source.getId().equalsIgnoreCase(target.getId())) {
/* 1709 */         ZimbraLog.imap.info("RENAME failed: cannot move folder between mailboxes");
/* 1710 */         sendNO(tag, "RENAME failed: cannot rename mailbox to other user's namespace");
/* 1711 */         return true; }
/* 1712 */       if (!newPath.isCreatable()) {
/* 1713 */         ZimbraLog.imap.info("RENAME failed: hidden folder or parent: %s", new Object[] { newPath });
/* 1714 */         sendNO(tag, "RENAME failed");
/* 1715 */         return true; }
/* 1716 */       if (!oldPath.isVisible()) {
/* 1717 */         throw MailServiceException.NO_SUCH_FOLDER(oldPath.asZimbraPath());
/*      */       }
/*      */       
/* 1720 */       Object mboxobj = oldPath.getOwnerMailbox();
/* 1721 */       if ((mboxobj instanceof Mailbox)) {
/* 1722 */         int folderId = oldPath.asItemId().getId();
/* 1723 */         if (folderId == 2) {
/* 1724 */           throw ImapServiceException.CANT_RENAME_INBOX();
/*      */         }
/* 1726 */         Mailbox mbox = (Mailbox)mboxobj;
/* 1727 */         mbox.rename(getContext(), folderId, MailItem.Type.FOLDER, "/" + newPath.asResolvedPath());
/* 1728 */       } else if ((mboxobj instanceof ZMailbox)) {
/* 1729 */         if (oldPath.asItemId().getId() == 2) {
/* 1730 */           throw ImapServiceException.CANT_RENAME_INBOX();
/*      */         }
/* 1732 */         ZMailbox zmbx = (ZMailbox)mboxobj;
/* 1733 */         ZFolder zfolder = (ZFolder)oldPath.getFolder();
/* 1734 */         zmbx.renameFolder(zfolder.getId(), "/" + newPath.asResolvedPath());
/*      */       } else {
/* 1736 */         ZimbraLog.imap.info("RENAME failed: cannot get mailbox for path: " + oldPath);
/* 1737 */         sendNO(tag, "RENAME failed");
/* 1738 */         return true;
/*      */       }
/*      */     } catch (ServiceException e) {
/* 1741 */       if (e.getCode().equals("imap.CANNOT_RENAME_INBOX")) {
/* 1742 */         ZimbraLog.imap.info("RENAME failed: RENAME of INBOX not supported");
/* 1743 */         sendNO(tag, "RENAME failed: RENAME of INBOX not supported");
/* 1744 */         return true; }
/* 1745 */       if (e.getCode().equals("mail.NO_SUCH_FOLDER")) {
/* 1746 */         ZimbraLog.imap.info("RENAME failed: no such folder: %s", new Object[] { oldPath });
/* 1747 */       } else if (e.getCode().equals("mail.IMMUTABLE_OBJECT")) {
/* 1748 */         ZimbraLog.imap.info("RENAME failed: cannot rename system folder: %s", new Object[] { oldPath });
/* 1749 */       } else if (e.getCode().equals("mail.CANNOT_CONTAIN")) {
/* 1750 */         ZimbraLog.imap.info("RENAME failed: invalid target folder: %s", new Object[] { newPath });
/*      */       } else {
/* 1752 */         ZimbraLog.imap.warn("RENAME failed", e);
/*      */       }
/* 1754 */       sendNO(tag, "RENAME failed");
/* 1755 */       return canContinue(e);
/*      */     }
/*      */     
/*      */ 
/* 1759 */     sendNotifications(true, false);
/* 1760 */     sendOK(tag, "RENAME completed");
/* 1761 */     return true;
/*      */   }
/*      */   
/*      */   boolean doSUBSCRIBE(String tag, ImapPath path) throws IOException {
/* 1765 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 1766 */       return true;
/*      */     }
/*      */     try
/*      */     {
/* 1770 */       path.canonicalize();
/*      */       
/* 1772 */       if (path.belongsTo(this.credentials)) {
/* 1773 */         if (!path.isVisible()) {
/* 1774 */           throw ImapServiceException.FOLDER_NOT_VISIBLE(path.asImapPath());
/*      */         }
/* 1776 */         Mailbox mbox = (Mailbox)path.getOwnerMailbox();
/* 1777 */         Folder folder = (Folder)path.getFolder();
/* 1778 */         if (!folder.isTagged(Flag.FlagInfo.SUBSCRIBED)) {
/* 1779 */           mbox.alterTag(getContext(), folder.getId(), MailItem.Type.FOLDER, Flag.FlagInfo.SUBSCRIBED, true, null);
/*      */         }
/*      */       } else {
/* 1782 */         this.credentials.subscribe(path);
/*      */       }
/*      */     } catch (ServiceException e) {
/* 1785 */       if (e.getCode().equals("mail.NO_SUCH_FOLDER")) {
/* 1786 */         ZimbraLog.imap.info("SUBSCRIBE failed: no such folder: %s", new Object[] { path });
/* 1787 */       } else if (e.getCode().equals("service.PERM_DENIED")) {
/* 1788 */         ZimbraLog.imap.info("SUBSCRIBE failed: permission denied on folder: %s", new Object[] { path });
/* 1789 */       } else if (e.getCode().equals("imap.FOLDER_NOT_VISIBLE")) {
/* 1790 */         ZimbraLog.imap.info("SUBSCRIBE failed: folder not visible: %s", new Object[] { path });
/*      */       } else {
/* 1792 */         ZimbraLog.imap.warn("SUBSCRIBE failed", e);
/*      */       }
/* 1794 */       sendNO(tag, "SUBSCRIBE failed");
/* 1795 */       return canContinue(e);
/*      */     }
/*      */     
/* 1798 */     sendNotifications(true, false);
/* 1799 */     sendOK(tag, "SUBSCRIBE completed");
/* 1800 */     return true;
/*      */   }
/*      */   
/*      */   boolean doUNSUBSCRIBE(String tag, ImapPath path) throws IOException {
/* 1804 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 1805 */       return true;
/*      */     }
/*      */     try {
/* 1808 */       if (path.belongsTo(this.credentials)) {
/*      */         try {
/* 1810 */           Mailbox mbox = this.credentials.getMailbox();
/* 1811 */           Folder folder = (Folder)path.getFolder();
/* 1812 */           if (folder.isTagged(Flag.FlagInfo.SUBSCRIBED)) {
/* 1813 */             mbox.alterTag(getContext(), folder.getId(), MailItem.Type.FOLDER, Flag.FlagInfo.SUBSCRIBED, false, null);
/*      */           }
/*      */         }
/*      */         catch (MailServiceException.NoSuchItemException e) {}
/*      */       }
/*      */       
/*      */ 
/* 1820 */       this.credentials.unsubscribe(path);
/*      */     } catch (MailServiceException.NoSuchItemException nsie) {
/* 1822 */       ZimbraLog.imap.info("UNSUBSCRIBE failure skipped: no such folder: %s", new Object[] { path });
/*      */     } catch (ServiceException e) {
/* 1824 */       ZimbraLog.imap.warn("UNSUBSCRIBE failed", e);
/* 1825 */       sendNO(tag, "UNSUBSCRIBE failed");
/* 1826 */       return canContinue(e);
/*      */     }
/*      */     
/* 1829 */     sendNotifications(true, false);
/* 1830 */     sendOK(tag, "UNSUBSCRIBE completed");
/* 1831 */     return true;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean doLIST(String tag, String referenceName, Set<String> mailboxNames, byte selectOptions, byte returnOptions, byte status)
/*      */     throws ImapException, IOException
/*      */   {
/* 1844 */     checkCommandThrottle(new ListCommand(referenceName, mailboxNames, selectOptions, returnOptions, status));
/* 1845 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 1846 */       return true;
/*      */     }
/* 1848 */     String command = (returnOptions & 0x4) != 0 ? "XLIST" : "LIST";
/*      */     
/* 1850 */     if ((selectOptions == 0) && ((returnOptions & 0xFFFFFFFB) == 0) && (mailboxNames.size() == 1) && (mailboxNames.contains("")))
/*      */     {
/*      */ 
/* 1853 */       String owner = new ImapPath(referenceName, this.credentials, ImapPath.Scope.UNPARSED).getOwner();
/* 1854 */       String root = owner == null ? "\"\"" : ImapPath.asUtf7String("/home/" + owner);
/*      */       
/* 1856 */       sendNotifications(true, false);
/* 1857 */       sendUntagged(command + " (\\NoSelect) \"/\" " + root);
/* 1858 */       sendOK(tag, command + " completed");
/* 1859 */       return true;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/* 1865 */     if (extensionEnabled("CHILDREN")) {
/* 1866 */       returnOptions = (byte)(returnOptions | 0x2);
/*      */     }
/*      */     
/*      */ 
/* 1870 */     boolean selectSubscribed = (selectOptions & 0x1) != 0;
/* 1871 */     if (selectSubscribed) {
/* 1872 */       returnOptions = (byte)(returnOptions | 0x1);
/*      */     }
/* 1874 */     boolean returnSubscribed = (returnOptions & 0x1) != 0;
/* 1875 */     Set<String> remoteSubscriptions = null;
/*      */     
/* 1877 */     boolean selectRecursive = (selectOptions & 0x4) != 0;
/*      */     
/* 1879 */     Map<ImapPath, Object> matches = new TreeMap();
/*      */     try {
/* 1881 */       if (returnSubscribed) {
/* 1882 */         remoteSubscriptions = this.credentials.listSubscriptions();
/*      */       }
/* 1884 */       paths = new HashMap();
/* 1885 */       Set<ImapPath> selected = new HashSet();
/* 1886 */       patterns = new ArrayList(mailboxNames.size());
/*      */       
/* 1888 */       for (String mailboxName : mailboxNames)
/*      */       {
/*      */ 
/*      */ 
/* 1892 */         if (!mailboxName.isEmpty())
/*      */         {
/*      */ 
/* 1895 */           Pair<String, Pattern> resolved = resolvePath(referenceName, mailboxName);
/* 1896 */           String resolvedPath = (String)resolved.getFirst();
/* 1897 */           Pattern pattern = (Pattern)resolved.getSecond();
/*      */           
/* 1899 */           ImapPath patternPath = new ImapPath(resolvedPath, this.credentials, ImapPath.Scope.UNPARSED);
/* 1900 */           String owner = patternPath.getOwner();
/*      */           
/* 1902 */           if ((owner != null) && ((owner.indexOf('*') != -1) || (owner.indexOf('%') != -1)))
/*      */           {
/*      */ 
/*      */ 
/* 1906 */             ZimbraLog.imap.info(command + " failed: wildcards not permitted in username " + patternPath);
/* 1907 */             sendNO(tag, command + " failed: wildcards not permitted in username");
/* 1908 */             return true;
/*      */           }
/*      */           
/*      */ 
/* 1912 */           if ((owner == null) || (!patternPath.belongsTo(this.credentials)))
/*      */           {
/*      */ 
/*      */ 
/* 1916 */             if ((owner != null) && (("/home/" + owner).equalsIgnoreCase(resolvedPath))) {
/* 1917 */               matches.put(patternPath, command + " (\\NoSelect) \"/\" " + patternPath.asUtf7String());
/*      */ 
/*      */             }
/*      */             else
/*      */             {
/* 1922 */               Account acct = patternPath.getOwnerAccount();
/* 1923 */               if (acct != null)
/*      */               {
/*      */ 
/* 1926 */                 patterns.add(pattern);
/*      */                 
/*      */ 
/* 1929 */                 accumulatePaths(patternPath.getOwnerMailbox(), owner, null, paths);
/*      */                 
/*      */ 
/* 1932 */                 if (selectSubscribed) {
/* 1933 */                   for (ImapPath path : paths.keySet()) {
/* 1934 */                     if (isPathSubscribed(path, remoteSubscriptions)) {
/* 1935 */                       selected.add(path);
/*      */                     }
/*      */                   }
/*      */                   
/* 1939 */                   if (remoteSubscriptions != null) {
/* 1940 */                     for (String sub : remoteSubscriptions) {
/* 1941 */                       ImapPath spath = new ImapPath(sub, this.credentials);
/* 1942 */                       if (!selected.contains(spath)) if ((owner == null ? 1 : 0) == (spath.getOwner() == null ? 1 : 0)) {
/* 1943 */                           selected.add(spath);
/*      */                         }
/*      */                     }
/*      */                   }
/*      */                 } else {
/* 1948 */                   selected.addAll(paths.keySet());
/*      */                 }
/*      */               }
/*      */             } }
/*      */         } }
/* 1953 */       for (Iterator i$ = selected.iterator(); i$.hasNext();) { path = (ImapPath)i$.next();
/* 1954 */         for (Pattern pattern : patterns) {
/* 1955 */           if (pathMatches(path, pattern)) {
/* 1956 */             String hit = command + " (" + getFolderAttrs(path, returnOptions, paths, remoteSubscriptions) + ") \"/\" " + path.asUtf7String();
/* 1957 */             if (status == 0) {
/* 1958 */               matches.put(path, hit); break;
/*      */             }
/* 1960 */             matches.put(path, new String[] { hit, status(path, status) });
/*      */             
/* 1962 */             break;
/*      */           }
/*      */         }
/*      */       }
/*      */       ImapPath path;
/* 1967 */       if (selectRecursive)
/* 1968 */         for (i$ = selected.iterator(); i$.hasNext();) { path = (ImapPath)i$.next();
/*      */           
/*      */ 
/* 1971 */           if (!matches.containsKey(path))
/*      */           {
/*      */ 
/* 1974 */             folderName = path.asZimbraPath();
/* 1975 */             for (index = folderName.length() + 1; (index = folderName.lastIndexOf('/', index - 1)) != -1;) {
/* 1976 */               parent = new ImapPath(path.getOwner(), folderName.substring(0, index), this.credentials);
/* 1977 */               for (Pattern pattern : patterns)
/* 1978 */                 if (pathMatches(parent, pattern))
/*      */                 {
/* 1980 */                   for (ImapPath cached : paths.keySet()) {
/* 1981 */                     if (cached.equals(parent)) {
/* 1982 */                       parent = cached;
/* 1983 */                       break;
/*      */                     }
/*      */                   }
/* 1986 */                   matches.put(parent, command + " (" + getFolderAttrs(parent, returnOptions, paths, remoteSubscriptions) + ") \"/\" " + parent.asUtf7String() + " (CHILDINFO (\"SUBSCRIBED\"))");
/*      */                 }
/*      */             } } } } catch (ServiceException e) { Map<ImapPath, ItemId> paths;
/*      */       List<Pattern> patterns;
/*      */       Iterator i$;
/*      */       ImapPath path;
/*      */       String folderName;
/*      */       int index;
/*      */       ImapPath parent;
/* 1995 */       ZimbraLog.imap.warn(command + " failed", e);
/* 1996 */       sendNO(tag, command + " failed");
/* 1997 */       return canContinue(e);
/*      */     }
/*      */     
/* 2000 */     if (!matches.isEmpty()) {
/* 2001 */       for (Object match : matches.values()) {
/* 2002 */         if ((match instanceof String[])) {
/* 2003 */           for (String response : (String[])match) {
/* 2004 */             sendUntagged(response);
/*      */           }
/*      */         } else {
/* 2007 */           sendUntagged((String)match);
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 2012 */     sendNotifications(true, false);
/* 2013 */     sendOK(tag, command + " completed");
/* 2014 */     return true;
/*      */   }
/*      */   
/* 2017 */   private static final boolean[] REGEXP_ESCAPED = new boolean[''];
/*      */   
/* 2019 */   static { REGEXP_ESCAPED[40] = (REGEXP_ESCAPED[41] = REGEXP_ESCAPED[46] = 1);
/* 2020 */     REGEXP_ESCAPED[91] = (REGEXP_ESCAPED[93] = REGEXP_ESCAPED[124] = 1);
/* 2021 */     REGEXP_ESCAPED[94] = (REGEXP_ESCAPED[36] = REGEXP_ESCAPED[63] = 1);
/* 2022 */     REGEXP_ESCAPED[123] = (REGEXP_ESCAPED[125] = REGEXP_ESCAPED[42] = 1);
/* 2023 */     REGEXP_ESCAPED[92] = true;
/*      */   }
/*      */   
/*      */   private static Pair<String, Pattern> resolvePath(String referenceName, String mailboxName) {
/* 2027 */     int startWildcards = referenceName.length();
/* 2028 */     String resolved = mailboxName;
/* 2029 */     if ((!mailboxName.startsWith("/")) && (!referenceName.trim().equals(""))) {
/* 2030 */       if (referenceName.endsWith("/")) {
/* 2031 */         resolved = referenceName + mailboxName;
/*      */       } else {
/* 2033 */         resolved = referenceName + '/' + mailboxName;
/*      */       }
/*      */     } else {
/* 2036 */       startWildcards = 0;
/*      */     }
/*      */     
/* 2039 */     String unescaped = resolved.toUpperCase();
/* 2040 */     StringBuffer escaped = new StringBuffer();
/* 2041 */     boolean previousStar = false;
/* 2042 */     boolean previousPercent = false;
/* 2043 */     for (int i = 0; i < unescaped.length(); i++) {
/* 2044 */       char c = unescaped.charAt(i);
/*      */       
/*      */ 
/* 2047 */       if ((c == '*') && (i >= startWildcards)) {
/* 2048 */         if (!previousStar) {
/* 2049 */           escaped.append(".*");
/*      */         }
/* 2051 */       } else if ((c == '%') && (i >= startWildcards)) {
/* 2052 */         if (!previousPercent) {
/* 2053 */           escaped.append("[^/]*");
/*      */         }
/* 2055 */       } else if ((c > '') || (REGEXP_ESCAPED[c] == 0)) {
/* 2056 */         escaped.append(c);
/*      */       } else {
/* 2058 */         escaped.append('\\').append(c);
/*      */       }
/* 2060 */       previousStar = c == '*';
/* 2061 */       previousPercent = c == '%';
/*      */     }
/* 2063 */     return new Pair(resolved, Pattern.compile(escaped.toString()));
/*      */   }
/*      */   
/*      */   private void accumulatePaths(Object mboxobj, String owner, ImapPath relativeTo, Map<ImapPath, ItemId> paths) throws ServiceException {
/* 2067 */     String root = "/" + relativeTo.asResolvedPath();
/* 2068 */     if ((mboxobj instanceof Mailbox)) {
/* 2069 */       Mailbox mbox = (Mailbox)mboxobj;
/* 2070 */       Collection<Folder> folders = mbox.getVisibleFolders(getContext());
/* 2071 */       if (folders == null) {
/* 2072 */         folders = mbox.getFolderById(getContext(), relativeTo == null ? 1 : relativeTo.asItemId().getId()).getSubfolderHierarchy();
/*      */       }
/*      */       
/* 2075 */       for (Folder folder : folders) {
/* 2076 */         if ((folder.getPath().startsWith(root)) && (!folder.getPath().equals(root)))
/*      */         {
/*      */ 
/* 2079 */           ImapPath path = relativeTo == null ? new ImapPath(owner, folder, this.credentials) : new ImapPath(owner, folder, relativeTo);
/*      */           
/* 2081 */           if (path.isVisible())
/* 2082 */             if ((this.userAgent == null) || (!this.userAgent.startsWith(IDInfo.DATASOURCE_IMAP_CLIENT_NAME)) || (!folder.isTagged(Flag.FlagInfo.SYNCFOLDER)))
/*      */             {
/*      */ 
/*      */ 
/*      */ 
/* 2087 */               boolean alreadyTraversed = paths.put(path, path.asItemId()) != null;
/* 2088 */               if (((folder instanceof Mountpoint)) && (!alreadyTraversed))
/* 2089 */                 accumulatePaths(path.getOwnerMailbox(), owner, path, paths);
/*      */             }
/*      */         }
/*      */       }
/* 2093 */     } else if ((mboxobj instanceof ZMailbox)) {
/* 2094 */       ZMailbox zmbx = (ZMailbox)mboxobj;
/* 2095 */       for (ZFolder zfolder : zmbx.getAllFolders()) {
/* 2096 */         if ((zfolder.getPath().startsWith(root)) && (!zfolder.getPath().equals(root)))
/*      */         {
/*      */ 
/* 2099 */           ImapPath path = relativeTo == null ? new ImapPath(owner, zfolder, this.credentials) : new ImapPath(owner, zfolder, relativeTo);
/* 2100 */           if (path.isVisible()) {
/* 2101 */             paths.put(path, path.asItemId());
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   private static boolean pathMatches(String path, Pattern pattern) throws ServiceException {
/* 2109 */     return AccessBoundedRegex.matches(path, pattern, Provisioning.getInstance().getConfig().getRegexMaxAccessesWhenMatching());
/*      */   }
/*      */   
/*      */   private static boolean pathMatches(SubscribedImapPath path, Pattern pattern)
/*      */     throws ServiceException
/*      */   {
/* 2115 */     return pathMatches(path.asImapPath().toUpperCase(), pattern);
/*      */   }
/*      */   
/*      */   private static boolean pathMatches(ImapPath path, Pattern pattern) throws ServiceException
/*      */   {
/* 2120 */     return pathMatches(path.asImapPath().toUpperCase(), pattern);
/*      */   }
/*      */   
/*      */   private String getFolderAttrs(ImapPath path, byte returnOptions, Map<ImapPath, ItemId> paths, Set<String> subscriptions) throws ServiceException
/*      */   {
/* 2125 */     StringBuilder attrs = new StringBuilder();
/*      */     
/* 2127 */     ItemId iid = (ItemId)paths.get(path);
/* 2128 */     if (iid == null) {
/* 2129 */       attrs.append(attrs.length() == 0 ? "" : " ").append("\\NonExistent");
/*      */     }
/* 2131 */     if (((returnOptions & 0x1) != 0) && (isPathSubscribed(path, subscriptions))) {
/* 2132 */       attrs.append(attrs.length() == 0 ? "" : " ").append("\\Subscribed");
/*      */     }
/* 2134 */     if (iid == null) {
/* 2135 */       return attrs.toString();
/*      */     }
/* 2137 */     boolean noinferiors = iid.getId() == 4;
/* 2138 */     if (noinferiors) {
/* 2139 */       attrs.append(attrs.length() == 0 ? "" : " ").append("\\NoInferiors");
/*      */     }
/* 2141 */     if (!path.isSelectable()) {
/* 2142 */       attrs.append(attrs.length() == 0 ? "" : " ").append("\\NoSelect");
/*      */     }
/* 2144 */     if ((!noinferiors) && ((returnOptions & 0x2) != 0)) {
/* 2145 */       String prefix = path.asZimbraPath().toUpperCase() + '/';
/* 2146 */       boolean children = false;
/* 2147 */       for (ImapPath other : paths.keySet()) {
/* 2148 */         if ((other.asZimbraPath().toUpperCase().startsWith(prefix)) && (other.isVisible())) {
/* 2149 */           children = true;
/* 2150 */           break;
/*      */         }
/*      */       }
/* 2153 */       attrs.append(attrs.length() == 0 ? "" : " ").append(children ? "\\HasChildren" : "\\HasNoChildren");
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 2158 */     if (((DebugConfig.imapForceSpecialUse) || ((returnOptions & 0x4) != 0)) && (path.belongsTo(this.credentials)))
/*      */     {
/* 2160 */       boolean returnXList = (returnOptions & 0x4) != 0;
/* 2161 */       switch (iid.getId()) {
/*      */       case 2: 
/* 2163 */         if (returnXList) {
/* 2164 */           attrs.append(attrs.length() == 0 ? "" : " ").append("\\Inbox");
/*      */         }
/*      */         break;
/*      */       case 6: 
/* 2168 */         attrs.append(attrs.length() == 0 ? "" : " ").append("\\Drafts");
/* 2169 */         break;
/*      */       case 3: 
/* 2171 */         attrs.append(attrs.length() == 0 ? "" : " ").append("\\Trash");
/* 2172 */         break;
/*      */       case 5: 
/* 2174 */         attrs.append(attrs.length() == 0 ? "" : " ").append("\\Sent");
/* 2175 */         break;
/*      */       case 4: 
/* 2177 */         attrs.append(attrs.length() == 0 ? "" : " ").append(returnXList ? "\\Spam" : "\\Junk");
/* 2178 */         break;
/*      */       default: 
/* 2180 */         String query = (path.getFolder() instanceof SearchFolder) ? ((SearchFolder)path.getFolder()).getQuery() : null;
/* 2181 */         if (query != null) {
/* 2182 */           if (query.equalsIgnoreCase("is:flagged")) {
/* 2183 */             attrs.append(attrs.length() == 0 ? "" : " ").append(returnXList ? "\\Starred" : "\\Flagged");
/* 2184 */           } else if (query.equalsIgnoreCase("is:local")) {
/* 2185 */             attrs.append(attrs.length() == 0 ? "" : " ").append(returnXList ? "\\AllMail" : "\\All");
/*      */           }
/*      */         }
/*      */         break;
/*      */       }
/*      */       
/*      */     }
/* 2192 */     return attrs.toString();
/*      */   }
/*      */   
/*      */   private boolean isPathSubscribed(ImapPath path, Set<String> subscriptions) throws ServiceException {
/* 2196 */     if (path.belongsTo(this.credentials)) {
/* 2197 */       Object folderObj = path.getFolder();
/* 2198 */       if ((folderObj instanceof Folder)) {
/* 2199 */         Folder folder = (Folder)path.getFolder();
/* 2200 */         return folder.isTagged(Flag.FlagInfo.SUBSCRIBED); }
/* 2201 */       if ((folderObj instanceof ZFolder)) {
/* 2202 */         ZFolder folder = (ZFolder)path.getFolder();
/* 2203 */         return folder.isIMAPSubscribed();
/*      */       }
/* 2205 */       ZimbraLog.imap.info("Unexpected class %s for folder for path %s", new Object[] { folderObj.getClass().getName(), path.asZimbraPath() });
/*      */ 
/*      */     }
/* 2208 */     else if ((subscriptions != null) && (!subscriptions.isEmpty())) {
/* 2209 */       for (String sub : subscriptions) {
/* 2210 */         if (sub.equalsIgnoreCase(path.asImapPath())) {
/* 2211 */           return true;
/*      */         }
/*      */       }
/*      */     }
/* 2215 */     return false;
/*      */   }
/*      */   
/*      */   boolean doLSUB(String tag, String referenceName, String mailboxName) throws ImapException, IOException {
/* 2219 */     checkCommandThrottle(new LsubCommand(referenceName, mailboxName));
/* 2220 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 2221 */       return true;
/*      */     }
/* 2223 */     Pair<String, Pattern> resolved = resolvePath(referenceName, mailboxName);
/* 2224 */     String resolvedPath = (String)resolved.getFirst();
/* 2225 */     Pattern pattern = (Pattern)resolved.getSecond();
/* 2226 */     Pattern childPattern = Pattern.compile(pattern.pattern() + "/.*");
/*      */     
/* 2228 */     ImapPath patternPath = new ImapPath(resolvedPath, this.credentials, ImapPath.Scope.UNPARSED);
/*      */     
/* 2230 */     List<String> subscriptions = null;
/*      */     try
/*      */     {
/* 2233 */       String owner = patternPath.getOwner();
/* 2234 */       if ((owner == null) || (owner.indexOf('*') != -1) || (owner.indexOf('%') != -1) || (!patternPath.belongsTo(this.credentials))) {
/* 2235 */         Map<SubscribedImapPath, Boolean> hits = new HashMap();
/*      */         
/* 2237 */         if (owner == null) {
/* 2238 */           Mailbox mbox = this.credentials.getMailbox();
/* 2239 */           for (Folder folder : mbox.getFolderById(getContext(), 1).getSubfolderHierarchy()) {
/* 2240 */             if (folder.isTagged(Flag.FlagInfo.SUBSCRIBED)) {
/* 2241 */               checkSubscription(new SubscribedImapPath(new ImapPath(null, folder, this.credentials)), pattern, childPattern, hits);
/*      */             }
/*      */           }
/*      */         }
/*      */         
/*      */ 
/* 2247 */         Set<String> remoteSubscriptions = this.credentials.listSubscriptions();
/* 2248 */         if ((remoteSubscriptions != null) && (!remoteSubscriptions.isEmpty())) {
/* 2249 */           for (String sub : remoteSubscriptions) {
/* 2250 */             ImapPath subscribed = new ImapPath(sub, this.credentials);
/* 2251 */             if ((owner == null ? 1 : 0) == (subscribed.getOwner() == null ? 1 : 0)) {
/* 2252 */               checkSubscription(new SubscribedImapPath(subscribed), pattern, childPattern, hits);
/*      */             }
/*      */           }
/*      */         }
/*      */         
/* 2257 */         subscriptions = new ArrayList(hits.size());
/* 2258 */         for (Map.Entry<SubscribedImapPath, Boolean> hit : hits.entrySet()) {
/* 2259 */           String attrs = ((Boolean)hit.getValue()).booleanValue() ? "" : "\\NoSelect";
/* 2260 */           subscriptions.add("LSUB (" + attrs + ") \"/\" " + ((SubscribedImapPath)hit.getKey()).asUtf7String());
/*      */         }
/*      */       }
/*      */     } catch (ServiceException e) {
/* 2264 */       ZimbraLog.imap.warn("LSUB failed", e);
/* 2265 */       sendNO(tag, "LSUB failed");
/* 2266 */       return canContinue(e);
/*      */     }
/*      */     
/* 2269 */     if (subscriptions != null) {
/* 2270 */       for (String sub : subscriptions) {
/* 2271 */         sendUntagged(sub);
/*      */       }
/*      */     }
/*      */     
/* 2275 */     sendNotifications(true, false);
/* 2276 */     sendOK(tag, "LSUB completed");
/* 2277 */     return true;
/*      */   }
/*      */   
/*      */   private class SubscribedImapPath
/*      */     implements Comparable<SubscribedImapPath>
/*      */   {
/*      */     private final String imapPathString;
/*      */     private final boolean validSubscribeImapPath;
/*      */     
/*      */     public SubscribedImapPath(ImapPath path)
/*      */       throws ServiceException
/*      */     {
/* 2289 */       this.validSubscribeImapPath = path.isValidImapPath();
/* 2290 */       this.imapPathString = path.asImapPath();
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     public boolean isValidSubscribeImapPath()
/*      */       throws ServiceException
/*      */     {
/* 2300 */       return this.validSubscribeImapPath;
/*      */     }
/*      */     
/* 2303 */     public String asImapPath() { return this.imapPathString; }
/*      */     
/*      */     public String asUtf7String() {
/* 2306 */       return ImapPath.asUtf7String(this.imapPathString);
/*      */     }
/*      */     
/*      */     public void addUnsubsribedMatchingParents(Pattern pattern, Map<SubscribedImapPath, Boolean> hits) throws ServiceException
/*      */     {
/* 2311 */       int delimiter = this.imapPathString.lastIndexOf('/');
/* 2312 */       String pathString = this.imapPathString;
/*      */       
/* 2314 */       while (delimiter > 0) {
/* 2315 */         ImapPath path = new ImapPath(pathString.substring(0, delimiter), ImapHandler.this.credentials);
/* 2316 */         pathString = path.asImapPath();
/* 2317 */         SubscribedImapPath subsPath = new SubscribedImapPath(ImapHandler.this, path);
/* 2318 */         if ((!hits.containsKey(subsPath)) && (ImapHandler.pathMatches(path, pattern))) {
/* 2319 */           hits.put(subsPath, Boolean.FALSE);
/*      */         }
/* 2321 */         delimiter = pathString.lastIndexOf('/');
/*      */       }
/*      */     }
/*      */     
/*      */     public int compareTo(SubscribedImapPath other)
/*      */     {
/* 2327 */       return asImapPath().compareToIgnoreCase(other.asImapPath());
/*      */     }
/*      */   }
/*      */   
/*      */   static final int STATUS_MESSAGES = 1;
/*      */   static final int STATUS_RECENT = 2;
/*      */   static final int STATUS_UIDNEXT = 4;
/*      */   static final int STATUS_UIDVALIDITY = 8;
/*      */   static final int STATUS_UNSEEN = 16;
/*      */   static final int STATUS_HIGHESTMODSEQ = 32;
/*      */   static final boolean IDLE_START = true;
/*      */   static final boolean IDLE_STOP = false;
/*      */   private static final String IMAP_READ_RIGHTS = "lr";
/*      */   private static final String IMAP_WRITE_RIGHTS = "sw";
/*      */   private static final String IMAP_INSERT_RIGHTS = "ick";
/*      */   private static final String IMAP_DELETE_RIGHTS = "xted";
/*      */   private static final String IMAP_ADMIN_RIGHTS = "a";
/*      */   private void checkSubscription(SubscribedImapPath path, Pattern pattern, Pattern childPattern, Map<SubscribedImapPath, Boolean> hits)
/*      */     throws ServiceException
/*      */   {
/* 2347 */     if (!path.isValidSubscribeImapPath()) {
/* 2348 */       return;
/*      */     }
/* 2350 */     if (pathMatches(path, pattern)) {
/* 2351 */       hits.put(path, Boolean.TRUE);
/* 2352 */       return; }
/* 2353 */     if (!pathMatches(path, childPattern)) {
/* 2354 */       return;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 2363 */     path.addUnsubsribedMatchingParents(pattern, hits);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean doSTATUS(String tag, ImapPath path, byte status)
/*      */     throws ImapException, IOException
/*      */   {
/* 2374 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 2375 */       return true;
/*      */     }
/*      */     try {
/* 2378 */       path.canonicalize();
/* 2379 */       if (!path.isVisible()) {
/* 2380 */         ZimbraLog.imap.info("STATUS failed: folder not visible: %s", new Object[] { path });
/* 2381 */         sendNO(tag, "STATUS failed");
/* 2382 */         return true;
/*      */       }
/*      */       
/* 2385 */       sendUntagged(status(path, status));
/*      */     } catch (ServiceException e) {
/* 2387 */       if (e.getCode().equals("mail.NO_SUCH_FOLDER")) {
/* 2388 */         ZimbraLog.imap.info("STATUS failed: no such folder: %s", new Object[] { path });
/*      */       } else {
/* 2390 */         ZimbraLog.imap.warn("STATUS failed", e);
/*      */       }
/* 2392 */       sendNO(tag, "STATUS failed");
/* 2393 */       return canContinue(e);
/*      */     }
/*      */     
/* 2396 */     sendNotifications(true, false);
/* 2397 */     sendOK(tag, "STATUS completed");
/* 2398 */     return true;
/*      */   }
/*      */   
/*      */   String status(ImapPath path, byte status) throws ImapException, ServiceException {
/* 2402 */     StringBuilder data = new StringBuilder("STATUS ").append(path.asUtf7String()).append(" (");
/* 2403 */     int empty = data.length();
/*      */     
/*      */ 
/* 2406 */     Object mboxobj = path.getOwnerMailbox();
/* 2407 */     int modseq; if ((mboxobj instanceof Mailbox)) {
/* 2408 */       Mailbox mbox = (Mailbox)mboxobj;
/* 2409 */       Folder folder = (Folder)path.getFolder();
/* 2410 */       ImapFolder i4folder = getSelectedFolder();
/*      */       
/* 2412 */       int messages = (int)folder.getItemCount();
/* 2413 */       int recent; int recent; if ((status & 0x2) == 0) {
/* 2414 */         recent = -1; } else { int recent;
/* 2415 */         if (messages == 0) {
/* 2416 */           recent = 0; } else { int recent;
/* 2417 */           if ((i4folder != null) && (path.isEquivalent(i4folder.getPath()))) {
/* 2418 */             recent = i4folder.getRecentCount();
/*      */           } else
/* 2420 */             recent = mbox.getImapRecent(getContext(), folder.getId());
/*      */         } }
/* 2422 */       int uidnext = (folder instanceof SearchFolder) ? -1 : folder.getImapUIDNEXT();
/* 2423 */       int uvv = ImapFolder.getUIDValidity(folder);
/* 2424 */       int unread = folder.getUnreadCount();
/* 2425 */       modseq = (folder instanceof SearchFolder) ? 0 : folder.getImapMODSEQ(); } else { int modseq;
/* 2426 */       if ((mboxobj instanceof ZMailbox)) {
/* 2427 */         ZFolder zfolder = (ZFolder)path.getFolder();
/* 2428 */         if (zfolder == null) {
/* 2429 */           throw MailServiceException.NO_SUCH_FOLDER(path.asImapPath());
/*      */         }
/* 2431 */         int messages = zfolder.getImapMessageCount();
/* 2432 */         int recent = 0;
/* 2433 */         int uidnext = zfolder.getImapUIDNEXT();
/* 2434 */         int uvv = ImapFolder.getUIDValidity(zfolder);
/* 2435 */         int unread = zfolder.getImapUnreadCount();
/* 2436 */         modseq = zfolder.getImapMODSEQ();
/*      */       } else {
/* 2438 */         throw AccountServiceException.NO_SUCH_ACCOUNT(path.getOwner()); } }
/*      */     int modseq;
/*      */     int unread;
/* 2441 */     int uvv; int uidnext; int recent; int messages; if ((messages >= 0) && ((status & 0x1) != 0)) {
/* 2442 */       data.append(data.length() != empty ? " " : "").append("MESSAGES ").append(messages);
/*      */     }
/* 2444 */     if ((recent >= 0) && ((status & 0x2) != 0)) {
/* 2445 */       data.append(data.length() != empty ? " " : "").append("RECENT ").append(recent);
/*      */     }
/*      */     
/* 2448 */     if ((uidnext > 0) && ((status & 0x4) != 0)) {
/* 2449 */       data.append(data.length() != empty ? " " : "").append("UIDNEXT ").append(uidnext);
/*      */     }
/* 2451 */     if ((uvv > 0) && ((status & 0x8) != 0)) {
/* 2452 */       data.append(data.length() != empty ? " " : "").append("UIDVALIDITY ").append(uvv);
/*      */     }
/* 2454 */     if ((unread >= 0) && ((status & 0x10) != 0)) {
/* 2455 */       data.append(data.length() != empty ? " " : "").append("UNSEEN ").append(unread);
/*      */     }
/* 2457 */     if ((modseq >= 0) && ((status & 0x20) != 0)) {
/* 2458 */       data.append(data.length() != empty ? " " : "").append("HIGHESTMODSEQ ").append(modseq);
/*      */     }
/*      */     
/* 2461 */     return ')';
/*      */   }
/*      */   
/*      */   boolean doAPPEND(String tag, ImapPath path, List<AppendMessage> appends) throws IOException, ImapException {
/* 2465 */     checkCommandThrottle(new AppendCommand(path, appends));
/* 2466 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 2467 */       return true;
/*      */     }
/* 2469 */     Object mboxobj = null;
/* 2470 */     List<Tag> newTags = new ArrayList();
/* 2471 */     List<Integer> createdIds = new ArrayList(appends.size());
/* 2472 */     StringBuilder appendHint = extensionEnabled("UIDPLUS") ? new StringBuilder() : null;
/*      */     try {
/* 2474 */       if (!path.isVisible())
/* 2475 */         throw ImapServiceException.FOLDER_NOT_VISIBLE(path.asImapPath());
/* 2476 */       if (!path.isWritable((short)4)) {
/* 2477 */         throw ImapServiceException.FOLDER_NOT_WRITABLE(path.asImapPath());
/*      */       }
/* 2479 */       mboxobj = path.getOwnerMailbox();
/* 2480 */       Object folderobj = path.getFolder();
/*      */       
/* 2482 */       Mailbox mbox = (mboxobj instanceof Mailbox) ? (Mailbox)mboxobj : this.credentials.getMailbox();
/* 2483 */       mbox.lock.lock();
/*      */       try {
/* 2485 */         flagset = ImapFlagCache.getSystemFlags(mbox);
/* 2486 */         tagset = (mboxobj instanceof Mailbox) ? new ImapFlagCache((Mailbox)mboxobj, getContext()) : new ImapFlagCache();
/*      */         
/* 2488 */         for (AppendMessage append : appends)
/* 2489 */           append.checkFlags(mbox, flagset, tagset, newTags);
/*      */       } finally { ImapFlagCache flagset;
/*      */         ImapFlagCache tagset;
/* 2492 */         mbox.lock.release();
/*      */       }
/*      */       
/*      */ 
/* 2496 */       for (AppendMessage append : appends) {
/* 2497 */         append.checkContent();
/*      */       }
/* 2499 */       for (AppendMessage append : appends) {
/* 2500 */         int id = append.storeContent(mboxobj, folderobj);
/* 2501 */         if (id > 0) {
/* 2502 */           createdIds.add(Integer.valueOf(id));
/*      */         }
/*      */       }
/*      */       
/* 2506 */       int uvv = (folderobj instanceof Folder) ? ImapFolder.getUIDValidity((Folder)folderobj) : ImapFolder.getUIDValidity((ZFolder)folderobj);
/* 2507 */       if ((appendHint != null) && (uvv > 0)) {
/* 2508 */         appendHint.append("[APPENDUID ").append(uvv).append(' ').append(ImapFolder.encodeSubsequence(createdIds)).append("] ");
/*      */       }
/*      */     }
/*      */     catch (ServiceException e) {
/* 2512 */       for (AppendMessage append : appends) {
/* 2513 */         append.cleanup();
/*      */       }
/* 2515 */       deleteTags(newTags);
/* 2516 */       deleteMessages(mboxobj, createdIds);
/*      */       
/* 2518 */       String msg = "APPEND failed";
/* 2519 */       if (e.getCode().equals("mail.NO_SUCH_FOLDER")) {
/* 2520 */         ZimbraLog.imap.info("APPEND failed: no such folder: " + path);
/*      */         
/*      */ 
/*      */ 
/* 2524 */         if (path.isCreatable()) {
/* 2525 */           msg = "[TRYCREATE] APPEND failed: no such mailbox";
/*      */         }
/* 2527 */       } else if (e.getCode().equals("mail.INVALID_NAME")) {
/* 2528 */         ZimbraLog.imap.info("APPEND failed: " + e.getMessage());
/* 2529 */       } else if (e.getCode().equals("imap.FOLDER_NOT_VISIBLE")) {
/* 2530 */         ZimbraLog.imap.info("APPEND failed: folder not visible: " + path);
/* 2531 */       } else if (e.getCode().equals("imap.FOLDER_NOT_WRITABLE")) {
/* 2532 */         ZimbraLog.imap.info("APPEND failed: folder not writable: " + path);
/* 2533 */       } else if (e.getCode().equals("mail.QUOTA_EXCEEDED")) {
/* 2534 */         ZimbraLog.imap.info("APPEND failed: quota exceeded");
/*      */       } else {
/* 2536 */         ZimbraLog.imap.warn("APPEND failed", e);
/*      */       }
/* 2538 */       sendNO(tag, msg);
/* 2539 */       return canContinue(e);
/*      */     }
/*      */     
/* 2542 */     sendNotifications(true, false);
/* 2543 */     sendOK(tag, (appendHint == null ? "" : appendHint.toString()) + "APPEND completed");
/* 2544 */     return true;
/*      */   }
/*      */   
/*      */   private void deleteTags(List<Tag> ltags) {
/* 2548 */     if ((ltags == null) || (ltags.isEmpty())) {
/* 2549 */       return;
/*      */     }
/* 2551 */     for (Tag ltag : ltags) {
/*      */       try
/*      */       {
/* 2554 */         ltag.getMailbox().delete(getContext(), ltag.getId(), ltag.getType(), null);
/*      */       } catch (ServiceException e) {
/* 2556 */         ZimbraLog.imap.warn("failed to delete tag: " + ltag.getName(), e);
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   public void deleteMessages(Object mboxobj, List<Integer> ids) {
/* 2562 */     for (Iterator i$ = ids.iterator(); i$.hasNext();) { int id = ((Integer)i$.next()).intValue();
/*      */       try {
/* 2564 */         if ((mboxobj instanceof Mailbox)) {
/* 2565 */           ((Mailbox)mboxobj).delete(getContext(), id, MailItem.Type.MESSAGE);
/*      */         } else {
/* 2567 */           ((ZMailbox)mboxobj).deleteMessage(String.valueOf(id));
/*      */         }
/*      */       } catch (ServiceException e) {
/* 2570 */         ZimbraLog.imap.warn("failed to delete message: " + id);
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean doIDLE(String tag, boolean begin, boolean success, ImapRequest req)
/*      */     throws IOException
/*      */   {
/* 2585 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 2586 */       return true;
/*      */     }
/* 2588 */     if (begin == true) {
/* 2589 */       this.idleTag = tag;
/* 2590 */       if (this.imapProxy != null) {
/* 2591 */         this.imapProxy.idle(req, begin);
/*      */       } else {
/* 2593 */         sendNotifications(true, false);
/* 2594 */         sendContinuation("idling");
/*      */       }
/*      */     } else {
/* 2597 */       tag = this.idleTag;
/* 2598 */       this.idleTag = null;
/* 2599 */       if (this.imapProxy != null) {
/* 2600 */         this.imapProxy.idle(req, begin);
/*      */       }
/* 2602 */       else if (success) {
/* 2603 */         sendOK(tag, "IDLE completed");
/*      */       } else {
/* 2605 */         sendBAD(tag, "IDLE stopped without DONE");
/*      */       }
/*      */     }
/*      */     
/* 2609 */     return true;
/*      */   }
/*      */   
/*      */   boolean doSETQUOTA(String tag) throws IOException {
/* 2613 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 2614 */       return true;
/*      */     }
/*      */     
/* 2617 */     sendNO(tag, "SETQUOTA failed");
/* 2618 */     return true;
/*      */   }
/*      */   
/*      */   boolean doGETQUOTA(String tag, ImapPath qroot) throws IOException {
/* 2622 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 2623 */       return true;
/*      */     }
/*      */     try {
/* 2626 */       if (!qroot.belongsTo(this.credentials)) {
/* 2627 */         ZimbraLog.imap.info("GETQUOTA failed: cannot get quota for other user's mailbox: " + qroot);
/* 2628 */         sendNO(tag, "GETQUOTA failed: permission denied");
/* 2629 */         return true;
/*      */       }
/*      */       
/* 2632 */       long quota = AccountUtil.getEffectiveQuota(this.credentials.getAccount());
/* 2633 */       if ((!qroot.asImapPath().equals("")) || (quota <= 0L)) {
/* 2634 */         ZimbraLog.imap.info("GETQUOTA failed: unknown quota root: '" + qroot + "'");
/* 2635 */         sendNO(tag, "GETQUOTA failed: unknown quota root");
/* 2636 */         return true;
/*      */       }
/*      */       
/* 2639 */       sendUntagged("QUOTA \"\" (STORAGE " + this.credentials.getMailbox().getSize() / 1024L + ' ' + quota / 1024L + ')');
/*      */     } catch (ServiceException e) {
/* 2641 */       ZimbraLog.imap.warn("GETQUOTA failed", e);
/* 2642 */       sendNO(tag, "GETQUOTA failed");
/* 2643 */       return canContinue(e);
/*      */     }
/*      */     
/* 2646 */     sendNotifications(true, false);
/* 2647 */     sendOK(tag, "GETQUOTA completed");
/* 2648 */     return true;
/*      */   }
/*      */   
/*      */   boolean doGETQUOTAROOT(String tag, ImapPath qroot) throws IOException {
/* 2652 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 2653 */       return true;
/*      */     }
/*      */     try {
/* 2656 */       if (!qroot.belongsTo(this.credentials)) {
/* 2657 */         ZimbraLog.imap.info("GETQUOTAROOT failed: cannot get quota root for other user's mailbox: " + qroot);
/* 2658 */         sendNO(tag, "GETQUOTAROOT failed: permission denied");
/* 2659 */         return true;
/*      */       }
/*      */       
/*      */ 
/* 2663 */       if (!qroot.isVisible()) {
/* 2664 */         ZimbraLog.imap.info("GETQUOTAROOT failed: folder not visible: '" + qroot + "'");
/* 2665 */         sendNO(tag, "GETQUOTAROOT failed");
/* 2666 */         return true;
/*      */       }
/*      */       
/*      */ 
/* 2670 */       long quota = AccountUtil.getEffectiveQuota(this.credentials.getAccount());
/* 2671 */       sendUntagged("QUOTAROOT " + qroot.asUtf7String() + (quota > 0L ? " \"\"" : ""));
/* 2672 */       if (quota > 0L) {
/* 2673 */         sendUntagged("QUOTA \"\" (STORAGE " + this.credentials.getMailbox().getSize() / 1024L + ' ' + quota / 1024L + ')');
/*      */       }
/*      */     } catch (ServiceException e) {
/* 2676 */       if (e.getCode().equals("mail.NO_SUCH_FOLDER")) {
/* 2677 */         ZimbraLog.imap.info("GETQUOTAROOT failed: no such folder: %s", new Object[] { qroot });
/*      */       } else {
/* 2679 */         ZimbraLog.imap.warn("GETQUOTAROOT failed", e);
/*      */       }
/* 2681 */       sendNO(tag, "GETQUOTAROOT failed");
/* 2682 */       return canContinue(e);
/*      */     }
/*      */     
/* 2685 */     sendNotifications(true, false);
/* 2686 */     sendOK(tag, "GETQUOTAROOT completed");
/* 2687 */     return true;
/*      */   }
/*      */   
/*      */   boolean doNAMESPACE(String tag) throws IOException {
/* 2691 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 2692 */       return true;
/*      */     }
/* 2694 */     sendUntagged("NAMESPACE ((\"\" \"/\")) ((\"/home/\" \"/\")) NIL");
/* 2695 */     sendNotifications(true, false);
/* 2696 */     sendOK(tag, "NAMESPACE completed");
/* 2697 */     return true;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private boolean allRightsPresent(String i4rights, String linked)
/*      */   {
/* 2708 */     for (int i = 0; i < linked.length(); i++) {
/* 2709 */       if (i4rights.indexOf(linked.charAt(i)) == -1) {
/* 2710 */         return false;
/*      */       }
/*      */     }
/* 2713 */     return true;
/*      */   }
/*      */   
/*      */   boolean doSETACL(String tag, ImapPath path, String principal, String i4rights, StoreAction action) throws IOException {
/* 2717 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 2718 */       return true;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/* 2724 */     short rights = 0;
/* 2725 */     for (int i = 0; i < i4rights.length(); i++) {
/* 2726 */       char c = i4rights.charAt(i);
/* 2727 */       if ("lr".indexOf(c) != -1) {
/* 2728 */         if (allRightsPresent(i4rights, "lr")) rights = (short)(rights | 0x1);
/* 2729 */       } else if ("sw".indexOf(c) != -1) {
/* 2730 */         if (allRightsPresent(i4rights, "sw")) rights = (short)(rights | 0x2);
/* 2731 */       } else if ("ick".indexOf(c) != -1) {
/* 2732 */         if (allRightsPresent(i4rights, "ick")) rights = (short)(rights | 0x4);
/* 2733 */       } else if ("xted".indexOf(c) != -1) {
/* 2734 */         if (allRightsPresent(i4rights, "xted")) rights = (short)(rights | 0x8);
/* 2735 */       } else if ("a".indexOf(c) != -1) {
/* 2736 */         if (allRightsPresent(i4rights, "a")) { rights = (short)(rights | 0x100);
/*      */         }
/*      */       }
/*      */       else
/*      */       {
/* 2741 */         ZimbraLog.imap.info("SETACL failed: invalid rights string: %s", new Object[] { i4rights });
/* 2742 */         sendBAD(tag, "SETACL failed: invalid right");
/* 2743 */         return true;
/*      */       }
/*      */     }
/*      */     
/*      */     try
/*      */     {
/* 2749 */       if ((path.getFolderRights() & 0x100) == 0) {
/* 2750 */         ZimbraLog.imap.info("SETACL failed: user does not have admin access: %s", new Object[] { path });
/* 2751 */         sendNO(tag, "SETACL failed");
/* 2752 */         return true;
/*      */       }
/*      */       
/*      */ 
/* 2756 */       if ((action != StoreAction.REPLACE) && (rights == 0)) {
/* 2757 */         sendNotifications(true, false);
/* 2758 */         sendOK(tag, "SETACL completed");
/* 2759 */         return true;
/*      */       }
/*      */       
/*      */ 
/* 2763 */       String granteeId = null;
/*      */       byte granteeType;
/* 2765 */       byte granteeType; if (principal.equals("anyone")) {
/* 2766 */         granteeId = "00000000-0000-0000-0000-000000000000";granteeType = 3;
/*      */       } else {
/* 2768 */         granteeType = 1;
/* 2769 */         NamedEntry entry = Provisioning.getInstance().get(Key.AccountBy.name, principal);
/* 2770 */         if (entry == null) {
/* 2771 */           entry = Provisioning.getInstance().get(Key.DistributionListBy.name, principal);
/* 2772 */           granteeType = 2;
/*      */         }
/* 2774 */         if (entry != null) {
/* 2775 */           granteeId = entry.getId();
/*      */         }
/*      */       }
/* 2778 */       if (granteeId == null) {
/* 2779 */         ZimbraLog.imap.info("SETACL failed: cannot resolve principal: %s", new Object[] { principal });
/* 2780 */         sendNO(tag, "SETACL failed");
/* 2781 */         return true;
/*      */       }
/*      */       
/*      */ 
/* 2785 */       short oldRights = 0;
/* 2786 */       Object folderobj = path.getFolder();
/* 2787 */       if ((folderobj instanceof Folder)) {
/* 2788 */         ACL acl = ((Folder)folderobj).getEffectiveACL();
/* 2789 */         if (acl != null) {
/* 2790 */           for (ACL.Grant grant : acl.getGrants()) {
/* 2791 */             if ((granteeId.equalsIgnoreCase(grant.getGranteeId())) || ((granteeType == 3) && ((grant.getGranteeType() == 3) || (grant.getGranteeType() == 6))))
/*      */             {
/*      */ 
/* 2794 */               oldRights = (short)(oldRights | grant.getGrantedRights());
/*      */             }
/*      */           }
/*      */         }
/*      */       } else {
/* 2799 */         for (ZGrant zgrant : ((ZFolder)folderobj).getGrants()) {
/* 2800 */           if ((granteeId.equalsIgnoreCase(zgrant.getGranteeId())) || ((granteeType == 3) && ((zgrant.getGranteeType() == ZGrant.GranteeType.all) || (zgrant.getGranteeType() == ZGrant.GranteeType.pub))))
/*      */           {
/*      */ 
/* 2803 */             oldRights = (short)(oldRights | ACL.stringToRights(zgrant.getPermissions()));
/*      */           }
/*      */         }
/*      */       }
/*      */       short newRights;
/*      */       short newRights;
/* 2809 */       if (action == StoreAction.REMOVE) {
/* 2810 */         newRights = (short)(oldRights & (rights ^ 0xFFFFFFFF)); } else { short newRights;
/* 2811 */         if (action == StoreAction.ADD) {
/* 2812 */           newRights = (short)(oldRights | rights);
/*      */         } else {
/* 2814 */           newRights = rights;
/*      */         }
/*      */       }
/*      */       
/* 2818 */       if (newRights != oldRights) {
/* 2819 */         if ((folderobj instanceof Folder)) {
/* 2820 */           Mailbox mbox = (Mailbox)path.getOwnerMailbox();
/* 2821 */           mbox.grantAccess(getContext(), ((Folder)folderobj).getId(), granteeId, granteeType, newRights, null);
/*      */         } else {
/* 2823 */           ZMailbox zmbx = (ZMailbox)path.getOwnerMailbox();
/* 2824 */           ZGrant.GranteeType type = granteeType == 3 ? ZGrant.GranteeType.all : ZGrant.GranteeType.usr;
/* 2825 */           zmbx.modifyFolderGrant(((ZFolder)folderobj).getId(), type, principal, ACL.rightsToString(newRights), null);
/*      */         }
/*      */       }
/*      */     } catch (ServiceException e) {
/* 2829 */       if (e.getCode().equals("service.PERM_DENIED")) {
/* 2830 */         ZimbraLog.imap.info("SETACL failed: permission denied on folder: %s", new Object[] { path });
/* 2831 */       } else if (e.getCode().equals("mail.NO_SUCH_FOLDER")) {
/* 2832 */         ZimbraLog.imap.info("SETACL failed: no such folder: %s", new Object[] { path });
/* 2833 */       } else if (e.getCode().equals("account.NO_SUCH_ACCOUNT")) {
/* 2834 */         ZimbraLog.imap.info("SETACL failed: no such account: %s", new Object[] { principal });
/*      */       } else {
/* 2836 */         ZimbraLog.imap.warn("SETACL failed", e);
/*      */       }
/* 2838 */       sendNO(tag, "SETACL failed");
/* 2839 */       return true;
/*      */     }
/*      */     
/* 2842 */     sendNotifications(true, false);
/* 2843 */     sendOK(tag, "SETACL completed");
/* 2844 */     return true;
/*      */   }
/*      */   
/*      */   boolean doDELETEACL(String tag, ImapPath path, String principal) throws IOException {
/* 2848 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 2849 */       return true;
/*      */     }
/*      */     try
/*      */     {
/* 2853 */       if ((path.getFolderRights() & 0x100) == 0) {
/* 2854 */         ZimbraLog.imap.info("DELETEACL failed: user does not have admin access: " + path);
/* 2855 */         sendNO(tag, "DELETEACL failed");
/* 2856 */         return true;
/*      */       }
/*      */       
/*      */ 
/* 2860 */       String granteeId = null;
/* 2861 */       if (principal.equals("anyone")) {
/* 2862 */         granteeId = "00000000-0000-0000-0000-000000000000";
/*      */       } else {
/* 2864 */         NamedEntry entry = Provisioning.getInstance().get(Key.AccountBy.name, principal);
/* 2865 */         if (entry == null) {
/* 2866 */           entry = Provisioning.getInstance().get(Key.DistributionListBy.name, principal);
/*      */         }
/* 2868 */         if (entry != null) {
/* 2869 */           granteeId = entry.getId();
/*      */         }
/*      */       }
/* 2872 */       if (granteeId == null) {
/* 2873 */         ZimbraLog.imap.info("DELETEACL failed: cannot resolve principal: %s", new Object[] { principal });
/* 2874 */         sendNO(tag, "DELETEACL failed");
/* 2875 */         return true;
/*      */       }
/*      */       
/*      */ 
/* 2879 */       Object mboxobj = path.getOwnerMailbox();
/* 2880 */       if ((mboxobj instanceof Mailbox)) {
/* 2881 */         Mailbox mbox = (Mailbox)mboxobj;
/* 2882 */         Folder folder = (Folder)path.getFolder();
/* 2883 */         if (folder.getEffectiveACL() != null) {
/* 2884 */           mbox.revokeAccess(getContext(), folder.getId(), granteeId);
/* 2885 */           if (granteeId == "00000000-0000-0000-0000-000000000000") {
/* 2886 */             mbox.revokeAccess(getContext(), folder.getId(), "99999999-9999-9999-9999-999999999999");
/*      */           }
/*      */         }
/*      */       } else {
/* 2890 */         ZMailbox zmbx = (ZMailbox)mboxobj;
/* 2891 */         ZFolder zfolder = (ZFolder)path.getFolder();
/* 2892 */         if (!zfolder.getGrants().isEmpty()) {
/* 2893 */           zmbx.modifyFolderRevokeGrant(zfolder.getId(), granteeId);
/* 2894 */           if (granteeId == "00000000-0000-0000-0000-000000000000") {
/* 2895 */             zmbx.modifyFolderRevokeGrant(zfolder.getId(), "99999999-9999-9999-9999-999999999999");
/*      */           }
/*      */         }
/*      */       }
/*      */     } catch (ServiceException e) {
/* 2900 */       if (e.getCode().equals("service.PERM_DENIED")) {
/* 2901 */         ZimbraLog.imap.info("DELETEACL failed: permission denied on folder: %s", new Object[] { path });
/* 2902 */       } else if (e.getCode().equals("mail.NO_SUCH_FOLDER")) {
/* 2903 */         ZimbraLog.imap.info("DELETEACL failed: no such folder: %s", new Object[] { path });
/* 2904 */       } else if (e.getCode().equals("account.NO_SUCH_ACCOUNT")) {
/* 2905 */         ZimbraLog.imap.info("DELETEACL failed: no such account: %s", new Object[] { principal });
/*      */       } else {
/* 2907 */         ZimbraLog.imap.warn("DELETEACL failed", e);
/*      */       }
/* 2909 */       sendNO(tag, "DELETEACL failed");
/* 2910 */       return true;
/*      */     }
/*      */     
/* 2913 */     sendNotifications(true, false);
/* 2914 */     sendOK(tag, "DELETEACL completed");
/* 2915 */     return true;
/*      */   }
/*      */   
/*      */   boolean doGETACL(String tag, ImapPath path) throws IOException {
/* 2919 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 2920 */       return true;
/*      */     }
/* 2922 */     StringBuilder i4acl = new StringBuilder("ACL ").append(path.asUtf7String());
/*      */     
/*      */     try
/*      */     {
/* 2926 */       if ((path.getFolderRights() & 0x100) == 0) {
/* 2927 */         ZimbraLog.imap.info("GETACL failed: user does not have admin access: %s", new Object[] { path });
/* 2928 */         sendNO(tag, "GETACL failed");
/* 2929 */         return true;
/*      */       }
/*      */       
/*      */ 
/* 2933 */       Account owner = path.getOwnerAccount();
/* 2934 */       if (owner != null) {
/* 2935 */         i4acl.append(" \"").append(owner.getName()).append("\" ").append("lrswickxteda");
/*      */       }
/*      */       
/* 2938 */       Short anyoneRights = null;
/* 2939 */       Object folderobj = path.getFolder();
/* 2940 */       if ((folderobj instanceof Folder)) {
/* 2941 */         ACL acl = ((Folder)folderobj).getEffectiveACL();
/* 2942 */         if (acl != null) {
/* 2943 */           for (ACL.Grant grant : acl.getGrants()) {
/* 2944 */             byte type = grant.getGranteeType();
/* 2945 */             short rights = grant.getGrantedRights();
/* 2946 */             if ((type == 3) || (type == 6)) {
/* 2947 */               anyoneRights = Short.valueOf((short)((anyoneRights == null ? 0 : anyoneRights.shortValue()) | rights));
/* 2948 */             } else if ((type == 1) || (type == 2)) {
/* 2949 */               NamedEntry entry = FolderAction.lookupGranteeByZimbraId(grant.getGranteeId(), type);
/* 2950 */               if (entry != null) {
/* 2951 */                 i4acl.append(" \"").append(entry.getName()).append("\" ").append(exportRights(rights));
/*      */               }
/*      */             }
/*      */           }
/*      */         }
/*      */       } else {
/* 2957 */         for (ZGrant zgrant : ((ZFolder)folderobj).getGrants()) {
/* 2958 */           ZGrant.GranteeType ztype = zgrant.getGranteeType();
/* 2959 */           short rights = ACL.stringToRights(zgrant.getPermissions());
/* 2960 */           if ((ztype == ZGrant.GranteeType.pub) || (ztype == ZGrant.GranteeType.all)) {
/* 2961 */             anyoneRights = Short.valueOf((short)((anyoneRights == null ? 0 : anyoneRights.shortValue()) | rights));
/* 2962 */           } else if ((ztype == ZGrant.GranteeType.usr) || (ztype == ZGrant.GranteeType.grp)) {
/* 2963 */             byte granteeType = ztype == ZGrant.GranteeType.usr ? 1 : 2;
/* 2964 */             NamedEntry entry = FolderAction.lookupGranteeByZimbraId(zgrant.getGranteeId(), granteeType);
/* 2965 */             if (entry != null) {
/* 2966 */               i4acl.append(" \"").append(entry.getName()).append("\" ").append(exportRights(rights));
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */       
/*      */ 
/* 2973 */       if (anyoneRights != null) {
/* 2974 */         i4acl.append(" anyone ").append(exportRights(anyoneRights.shortValue()));
/*      */       }
/*      */     } catch (ServiceException e) {
/* 2977 */       if (e.getCode().equals("service.PERM_DENIED")) {
/* 2978 */         ZimbraLog.imap.info("GETACL failed: permission denied on folder: %s", new Object[] { path });
/* 2979 */       } else if (e.getCode().equals("mail.NO_SUCH_FOLDER")) {
/* 2980 */         ZimbraLog.imap.info("GETACL failed: no such folder: %s", new Object[] { path });
/*      */       } else {
/* 2982 */         ZimbraLog.imap.warn("GETACL failed", e);
/*      */       }
/* 2984 */       sendNO(tag, "GETACL failed");
/* 2985 */       return true;
/*      */     }
/*      */     
/* 2988 */     sendUntagged(i4acl.toString());
/* 2989 */     sendNotifications(true, false);
/* 2990 */     sendOK(tag, "GETACL completed");
/* 2991 */     return true;
/*      */   }
/*      */   
/*      */ 
/* 2995 */   private final short SUBFOLDER_RIGHTS = 5;
/*      */   private static final String IMAP_CONCATENATED_RIGHTS = "lrswickxteda";
/*      */   private static final String IMAP_DELIMITED_RIGHTS = "lr sw ick xted a";
/*      */   
/* 2999 */   private String exportRights(short rights) { StringBuilder imapRights = new StringBuilder(12);
/* 3000 */     if ((rights & 0x1) == 1) {
/* 3001 */       imapRights.append("lr");
/*      */     }
/* 3003 */     if ((rights & 0x2) == 2) {
/* 3004 */       imapRights.append("sw");
/*      */     }
/* 3006 */     if ((rights & 0x4) == 4) {
/* 3007 */       imapRights.append("ic");
/*      */     }
/* 3009 */     if ((rights & 0x5) == 5) {
/* 3010 */       imapRights.append("k");
/*      */     }
/* 3012 */     if ((rights & 0x8) == 8) {
/* 3013 */       imapRights.append("xted");
/*      */     }
/* 3015 */     if ((rights & 0x100) == 256) {
/* 3016 */       imapRights.append("a");
/*      */     }
/* 3018 */     return imapRights.length() == 0 ? "\"\"" : imapRights.toString();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean doLISTRIGHTS(String tag, ImapPath path, String principal)
/*      */     throws IOException
/*      */   {
/* 3030 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 3031 */       return true;
/*      */     }
/* 3033 */     boolean isOwner = false;
/*      */     try {
/* 3035 */       if (!principal.equals("anyone")) {
/* 3036 */         Account acct = Provisioning.getInstance().get(Key.AccountBy.name, principal);
/* 3037 */         if (acct == null) {
/* 3038 */           throw AccountServiceException.NO_SUCH_ACCOUNT(principal);
/*      */         }
/* 3040 */         isOwner = path.belongsTo(acct.getId());
/*      */       }
/*      */       
/* 3043 */       if ((path.getFolderRights() & 0x100) == 0) {
/* 3044 */         throw ServiceException.PERM_DENIED("you must have admin privileges to perform LISTRIGHTS");
/*      */       }
/*      */     } catch (ServiceException e) {
/* 3047 */       if (e.getCode().equals("service.PERM_DENIED")) {
/* 3048 */         ZimbraLog.imap.info("LISTRIGHTS failed: permission denied on folder: %s", new Object[] { path });
/* 3049 */       } else if (e.getCode().equals("mail.NO_SUCH_FOLDER")) {
/* 3050 */         ZimbraLog.imap.info("LISTRIGHTS failed: no such folder: %s", new Object[] { path });
/* 3051 */       } else if (e.getCode().equals("account.NO_SUCH_ACCOUNT")) {
/* 3052 */         ZimbraLog.imap.info("LISTRIGHTS failed: no such account: %s", new Object[] { principal });
/*      */       } else {
/* 3054 */         ZimbraLog.imap.warn("LISTRIGHTS failed", e);
/*      */       }
/* 3056 */       sendNO(tag, "LISTRIGHTS failed");
/* 3057 */       return canContinue(e);
/*      */     }
/*      */     
/* 3060 */     if (isOwner) {
/* 3061 */       sendUntagged("LISTRIGHTS " + path.asUtf7String() + " \"" + principal + "\" " + "lrswickxteda");
/*      */     } else {
/* 3063 */       sendUntagged("LISTRIGHTS " + path.asUtf7String() + " \"" + principal + "\" \"\" " + "lr sw ick xted a");
/*      */     }
/* 3065 */     sendNotifications(true, false);
/* 3066 */     sendOK(tag, "LISTRIGHTS completed");
/* 3067 */     return true;
/*      */   }
/*      */   
/*      */   boolean doMYRIGHTS(String tag, ImapPath path) throws IOException {
/* 3071 */     if (!checkState(tag, State.AUTHENTICATED)) {
/* 3072 */       return true;
/*      */     }
/*      */     short rights;
/*      */     try {
/* 3076 */       if (!path.isVisible()) {
/* 3077 */         throw ServiceException.PERM_DENIED("path not visible");
/*      */       }
/* 3079 */       rights = path.getFolderRights();
/*      */     } catch (ServiceException e) {
/* 3081 */       if (e.getCode().equals("service.PERM_DENIED")) {
/* 3082 */         ZimbraLog.imap.info("MYRIGHTS failed: permission denied on folder: %s", new Object[] { path });
/* 3083 */       } else if (e.getCode().equals("mail.NO_SUCH_FOLDER")) {
/* 3084 */         ZimbraLog.imap.info("MYRIGHTS failed: no such folder: %s", new Object[] { path });
/* 3085 */       } else if (e.getCode().equals("account.NO_SUCH_ACCOUNT")) {
/* 3086 */         ZimbraLog.imap.info("MYRIGHTS failed: no such account: %s", new Object[] { path.getOwner() });
/*      */       } else {
/* 3088 */         ZimbraLog.imap.warn("MYRIGHTS failed", e);
/*      */       }
/* 3090 */       sendNO(tag, "MYRIGHTS failed");
/* 3091 */       return canContinue(e);
/*      */     }
/*      */     
/* 3094 */     sendUntagged("MYRIGHTS " + path.asUtf7String() + ' ' + exportRights(rights));
/* 3095 */     sendNotifications(true, false);
/* 3096 */     sendOK(tag, "MYRIGHTS completed");
/* 3097 */     return true;
/*      */   }
/*      */   
/*      */   boolean doCHECK(String tag) throws IOException {
/* 3101 */     if (!checkState(tag, State.SELECTED)) {
/* 3102 */       return true;
/*      */     }
/* 3104 */     sendNotifications(true, false);
/* 3105 */     sendOK(tag, "CHECK completed");
/* 3106 */     return true;
/*      */   }
/*      */   
/*      */   boolean doCLOSE(String tag) throws IOException, ImapException {
/* 3110 */     if (!checkState(tag, State.SELECTED)) {
/* 3111 */       return true;
/*      */     }
/* 3113 */     ImapProxy proxy = this.imapProxy;
/* 3114 */     if (proxy != null) {
/* 3115 */       proxy.proxy(tag, "CLOSE");
/* 3116 */       unsetSelectedFolder(false);
/* 3117 */       return true;
/*      */     }
/*      */     
/* 3120 */     ImapFolder i4folder = getSelectedFolder();
/* 3121 */     if (i4folder == null) {
/* 3122 */       throw new ImapSessionClosedException();
/*      */     }
/* 3124 */     boolean expunged = false;
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     try
/*      */     {
/* 3132 */       if ((i4folder.isWritable()) && (i4folder.getPath().isWritable((short)8))) {
/* 3133 */         expunged = expungeMessages(tag, i4folder, null);
/*      */       }
/*      */     }
/*      */     catch (ServiceException e) {
/* 3137 */       ZimbraLog.imap.warn("error during CLOSE", e);
/*      */     }
/*      */     
/* 3140 */     String status = "";
/*      */     try {
/* 3142 */       if ((expunged) && (!i4folder.isVirtual()) && (sessionActivated(ImapExtension.QRESYNC))) {
/* 3143 */         status = "[HIGHESTMODSEQ " + i4folder.getCurrentMODSEQ() + "] ";
/*      */       }
/*      */     } catch (ServiceException e) {
/* 3146 */       ZimbraLog.imap.info("error while determining HIGHESTMODSEQ of selected folder", e);
/*      */     }
/*      */     
/* 3149 */     unsetSelectedFolder(true);
/*      */     
/* 3151 */     sendOK(tag, status + "CLOSE completed");
/* 3152 */     return true;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   boolean doUNSELECT(String tag)
/*      */     throws IOException
/*      */   {
/* 3160 */     if (!checkState(tag, State.SELECTED)) {
/* 3161 */       return true;
/*      */     }
/* 3163 */     unsetSelectedFolder(true);
/*      */     
/* 3165 */     sendOK(tag, "UNSELECT completed");
/* 3166 */     return true;
/*      */   }
/*      */   
/* 3169 */   private final int SUGGESTED_DELETE_BATCH_SIZE = 30;
/*      */   private static final int RETURN_MIN = 1;
/*      */   
/* 3172 */   boolean doEXPUNGE(String tag, boolean byUID, String sequenceSet) throws IOException, ImapException { if (!checkState(tag, State.SELECTED)) {
/* 3173 */       return true;
/*      */     }
/*      */     
/* 3176 */     ImapFolder i4folder = getSelectedFolder();
/* 3177 */     if (i4folder == null) {
/* 3178 */       throw new ImapSessionClosedException();
/*      */     }
/* 3180 */     if (!i4folder.isWritable()) {
/* 3181 */       sendNO(tag, "mailbox selected READ-ONLY");
/* 3182 */       return true;
/*      */     }
/*      */     
/* 3185 */     String command = byUID ? "UID EXPUNGE" : "EXPUNGE";
/*      */     boolean expunged;
/*      */     try {
/* 3188 */       if (!i4folder.getPath().isWritable((short)8)) {
/* 3189 */         throw ServiceException.PERM_DENIED("you do not have permission to delete messages from this folder");
/*      */       }
/* 3191 */       expunged = expungeMessages(tag, i4folder, sequenceSet);
/*      */     } catch (ServiceException e) {
/* 3193 */       ZimbraLog.imap.warn("%s failed", command, e);
/* 3194 */       sendNO(tag, command + " failed");
/* 3195 */       return canContinue(e);
/*      */     }
/*      */     
/* 3198 */     String status = "";
/*      */     try {
/* 3200 */       if ((expunged) && (byUID) && (!i4folder.isVirtual()) && (sessionActivated(ImapExtension.QRESYNC))) {
/* 3201 */         status = "[HIGHESTMODSEQ " + i4folder.getCurrentMODSEQ() + "] ";
/*      */       }
/*      */     } catch (ServiceException e) {
/* 3204 */       ZimbraLog.imap.info("error while determining HIGHESTMODSEQ of selected folder", e);
/*      */     }
/*      */     
/* 3207 */     sendNotifications(true, false);
/* 3208 */     sendOK(tag, status + command + " completed");
/* 3209 */     return true;
/*      */   }
/*      */   
/*      */   private boolean expungeMessages(String tag, ImapFolder i4folder, String sequenceSet) throws ServiceException, IOException, ImapParseException
/*      */   {
/*      */     Set<ImapMessage> i4set;
/* 3215 */     synchronized (i4folder.getMailbox()) {
/* 3216 */       i4set = sequenceSet == null ? null : i4folder.getSubsequence(tag, sequenceSet, true);
/*      */     }
/* 3218 */     List<Integer> ids = new ArrayList(30);
/*      */     
/* 3220 */     boolean changed = false;
/* 3221 */     long checkpoint = System.currentTimeMillis();
/* 3222 */     int i = 1; for (int max = i4folder.getSize(); i <= max; i++) {
/* 3223 */       ImapMessage i4msg = i4folder.getBySequence(i);
/* 3224 */       if ((i4msg != null) && (!i4msg.isExpunged()) && ((i4msg.flags & Flag.BITMASK_DELETED) > 0) && (
/* 3225 */         (i4set == null) || (i4set.contains(i4msg)))) {
/* 3226 */         ids.add(Integer.valueOf(i4msg.msgId));
/* 3227 */         changed = true;
/*      */       }
/*      */       
/*      */ 
/* 3231 */       if (ids.size() >= (i == max ? 1 : 30)) {
/* 3232 */         List<Integer> nonExistingItems = new ArrayList();
/* 3233 */         ZimbraLog.imap.debug("  ** deleting: %s", new Object[] { ids });
/* 3234 */         this.selectedFolder.getMailbox().delete(getContext(), ArrayUtil.toIntArray(ids), MailItem.Type.UNKNOWN, null, nonExistingItems);
/* 3235 */         ids.clear();
/* 3236 */         for (Integer itemId : nonExistingItems) {
/* 3237 */           i4msg = i4folder.getById(itemId.intValue());
/* 3238 */           if (i4msg != null) {
/* 3239 */             i4msg.setExpunged(true);
/*      */           }
/*      */         }
/* 3242 */         nonExistingItems.clear();
/*      */         
/*      */ 
/* 3245 */         long now = System.currentTimeMillis();
/* 3246 */         if (now - checkpoint > 15000L) {
/* 3247 */           sendIdleUntagged();
/* 3248 */           checkpoint = now;
/*      */         }
/*      */       }
/*      */     }
/* 3252 */     if (changed) {
/* 3253 */       this.selectedFolder.getMailbox().resetRecentMessageCount(getContext());
/*      */     }
/* 3255 */     return changed;
/*      */   }
/*      */   
/*      */ 
/*      */   private static final int RETURN_MAX = 2;
/*      */   
/*      */   private static final int RETURN_ALL = 4;
/*      */   private static final int RETURN_COUNT = 8;
/*      */   private static final int RETURN_SAVE = 16;
/*      */   private static final int LARGEST_FOLDER_BATCH = 600;
/* 3265 */   public static final Set<MailItem.Type> ITEM_TYPES = ImapMessage.SUPPORTED_TYPES;
/*      */   static final int FETCH_BODY = 1;
/*      */   static final int FETCH_BODYSTRUCTURE = 2;
/*      */   
/* 3269 */   boolean doSEARCH(String tag, ImapSearch i4search, boolean byUID, Integer options) throws IOException, ImapException { checkCommandThrottle(new SearchCommand(i4search, options));
/* 3270 */     return search(tag, "SEARCH", i4search, byUID, options, null);
/*      */   }
/*      */   
/*      */   boolean doSORT(String tag, ImapSearch i4search, boolean byUID, Integer options, List<SortBy> order) throws IOException, ImapException
/*      */   {
/* 3275 */     checkCommandThrottle(new SortCommand(i4search, options));
/* 3276 */     return search(tag, "SORT", i4search, byUID, options, order);
/*      */   }
/*      */   
/*      */   boolean search(String tag, String command, ImapSearch i4search, boolean byUID, Integer options, List<SortBy> order) throws IOException, ImapException
/*      */   {
/* 3281 */     if (!checkState(tag, State.SELECTED)) {
/* 3282 */       return true;
/*      */     }
/* 3284 */     ImapFolder i4folder = getSelectedFolder();
/* 3285 */     if (i4folder == null) {
/* 3286 */       throw new ImapSessionClosedException();
/*      */     }
/* 3288 */     boolean requiresMODSEQ = i4search.requiresMODSEQ();
/* 3289 */     if (requiresMODSEQ) {
/* 3290 */       activateExtension(ImapExtension.CONDSTORE);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 3298 */     if ((requiresMODSEQ) && (!sessionActivated(ImapExtension.CONDSTORE))) {
/* 3299 */       throw new ImapParseException(tag, "NOMODSEQ", "cannot SEARCH MODSEQ in this mailbox", true);
/*      */     }
/*      */     
/* 3302 */     SortBy sort = SortBy.NONE;
/* 3303 */     if ((order != null) && (!order.isEmpty())) {
/* 3304 */       for (SortBy level : order) {
/* 3305 */         if ((sort = level) != SortBy.NONE) {
/*      */           break;
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 3311 */     boolean saveResults = (options != null) && ((options.intValue() & 0x10) != 0);
/* 3312 */     boolean unsorted = sort == SortBy.NONE;
/*      */     
/* 3314 */     int modseq = 0;
/*      */     Collection<ImapMessage> hits;
/*      */     try {
/* 3317 */       Mailbox mbox = i4folder.getMailbox();
/* 3318 */       if ((unsorted) && (i4search.canBeRunLocally())) {
/* 3319 */         mbox.lock.lock(false);
/*      */         try {
/* 3321 */           Collection<ImapMessage> hits = i4search.evaluate(i4folder);
/* 3322 */           hits.remove(null);
/*      */         } finally {
/* 3324 */           mbox.lock.release();
/*      */         }
/*      */       } else {
/* 3327 */         ZimbraQueryResults zqr = runSearch(i4search, i4folder, sort, requiresMODSEQ ? SearchParams.Fetch.MODSEQ : SearchParams.Fetch.IDS);
/*      */         
/* 3329 */         hits = unsorted ? new ImapMessage.ImapMessageSet() : new ArrayList();
/*      */         try {
/* 3331 */           for (ZimbraHit hit = zqr.getNext(); hit != null; hit = zqr.getNext()) {
/* 3332 */             ImapMessage i4msg = i4folder.getById(hit.getItemId());
/* 3333 */             if ((i4msg != null) && (!i4msg.isExpunged()))
/*      */             {
/*      */ 
/* 3336 */               hits.add(i4msg);
/* 3337 */               if (requiresMODSEQ)
/* 3338 */                 modseq = Math.max(modseq, hit.getModifiedSequence());
/*      */             }
/*      */           }
/* 3341 */         } finally { Closeables.closeQuietly(zqr);
/*      */         }
/*      */         
/*      */       }
/*      */     }
/*      */     catch (ServiceException e)
/*      */     {
/* 3348 */       if (saveResults) {
/* 3349 */         i4folder.saveSearchResults(new ImapMessage.ImapMessageSet());
/*      */       }
/* 3351 */       ZimbraLog.imap.warn(command + " failed", e);
/* 3352 */       sendNO(tag, command + " failed");
/* 3353 */       return true;
/*      */     }
/*      */     
/* 3356 */     int size = hits.size();
/* 3357 */     ImapMessage first = null;ImapMessage last = null;
/* 3358 */     if ((size != 0) && (options != null) && ((options.intValue() & 0x3) != 0)) {
/* 3359 */       if (unsorted) {
/* 3360 */         first = (ImapMessage)((ImapMessage.ImapMessageSet)hits).first();
/* 3361 */         last = (ImapMessage)((ImapMessage.ImapMessageSet)hits).last();
/*      */       } else {
/* 3363 */         first = (ImapMessage)((List)hits).get(0);
/* 3364 */         last = (ImapMessage)((List)hits).get(size - 1);
/*      */       }
/*      */     }
/*      */     
/* 3368 */     StringBuilder result = null;
/* 3369 */     if (options == null) {
/* 3370 */       result = new StringBuilder(command);
/* 3371 */       for (ImapMessage i4msg : hits) {
/* 3372 */         result.append(' ').append(getMessageId(i4msg, byUID));
/*      */       }
/* 3374 */     } else if (options.intValue() != 16)
/*      */     {
/*      */ 
/* 3377 */       result = new StringBuilder("ESEARCH (TAG \"").append(tag).append("\")");
/* 3378 */       if (byUID) {
/* 3379 */         result.append(" UID");
/*      */       }
/* 3381 */       if ((first != null) && ((options.intValue() & 0x1) != 0)) {
/* 3382 */         result.append(" MIN ").append(getMessageId(first, byUID));
/*      */       }
/* 3384 */       if ((last != null) && ((options.intValue() & 0x2) != 0)) {
/* 3385 */         result.append(" MAX ").append(getMessageId(last, byUID));
/*      */       }
/* 3387 */       if ((options.intValue() & 0x8) != 0) {
/* 3388 */         result.append(" COUNT ").append(size);
/*      */       }
/* 3390 */       if ((size != 0) && ((options.intValue() & 0x4) != 0)) {
/* 3391 */         result.append(" ALL ").append(ImapFolder.encodeSubsequence(hits, byUID));
/*      */       }
/*      */     }
/*      */     
/* 3395 */     if ((modseq > 0) && (result != null)) {
/* 3396 */       result.append(" (MODSEQ ").append(modseq).append(')');
/*      */     }
/* 3398 */     if (saveResults) {
/* 3399 */       if ((size == 0) || (options.intValue() == 16) || ((options.intValue() & 0xC) != 0)) {
/* 3400 */         i4folder.saveSearchResults(unsorted ? (ImapMessage.ImapMessageSet)hits : new ImapMessage.ImapMessageSet(hits));
/*      */       } else {
/* 3402 */         ImapMessage.ImapMessageSet saved = new ImapMessage.ImapMessageSet();
/* 3403 */         if ((first != null) && ((options.intValue() & 0x1) != 0)) {
/* 3404 */           saved.add(first);
/*      */         }
/* 3406 */         if ((last != null) && ((options.intValue() & 0x2) != 0)) {
/* 3407 */           saved.add(last);
/*      */         }
/* 3409 */         i4folder.saveSearchResults(saved);
/*      */       }
/*      */     }
/*      */     
/* 3413 */     if (result != null) {
/* 3414 */       sendUntagged(result.toString());
/*      */     }
/* 3416 */     sendNotifications(byUID, false);
/* 3417 */     sendOK(tag, (byUID ? "UID " : "") + command + " completed");
/* 3418 */     return true;
/*      */   }
/*      */   
/*      */   private static int getMessageId(ImapMessage i4msg, boolean byUID) {
/* 3422 */     return byUID ? i4msg.imapUid : i4msg.sequence;
/*      */   }
/*      */   
/*      */   private ZimbraQueryResults runSearch(ImapSearch i4search, ImapFolder i4folder, SortBy sort, SearchParams.Fetch fetch) throws ImapParseException, ServiceException
/*      */   {
/* 3427 */     Mailbox mbox = i4folder.getMailbox();
/* 3428 */     if (mbox == null) {
/* 3429 */       throw ServiceException.FAILURE("unexpected session close during search", null);
/*      */     }
/* 3431 */     Account acct = this.credentials == null ? null : this.credentials.getAccount();
/* 3432 */     TimeZone tz = acct == null ? null : WellKnownTimeZones.getTimeZoneById(acct.getAttr("zimbraPrefTimeZoneId"));
/*      */     
/*      */ 
/* 3435 */     mbox.lock.lock(false);
/*      */     String search;
/* 3437 */     try { search = i4search.toZimbraSearch(i4folder);
/* 3438 */       if (!i4folder.isVirtual()) {
/* 3439 */         search = "in:" + i4folder.getQuotedPath() + ' ' + search;
/* 3440 */       } else if (i4folder.getSize() <= 600) {
/* 3441 */         search = ImapSearch.sequenceAsSearchTerm(i4folder, i4folder.getAllMessages(), false) + ' ' + search;
/*      */       } else {
/* 3443 */         search = '(' + i4folder.getQuery() + ") " + search;
/*      */       }
/* 3445 */       ZimbraLog.imap.info("[ search is: " + search + " ]");
/*      */     } finally {
/* 3447 */       mbox.lock.release();
/*      */     }
/*      */     
/* 3450 */     SearchParams params = new SearchParams();
/* 3451 */     params.setIncludeTagDeleted(true);
/* 3452 */     params.setQueryString(search);
/* 3453 */     params.setTypes(i4folder.getTypeConstraint());
/* 3454 */     params.setSortBy(sort);
/* 3455 */     params.setChunkSize(2000);
/* 3456 */     params.setPrefetch(false);
/* 3457 */     params.setFetchMode(fetch);
/* 3458 */     params.setTimeZone(tz);
/*      */     
/* 3460 */     return mbox.index.search(SoapProtocol.Soap12, getContext(), params);
/*      */   }
/*      */   
/*      */   boolean doTHREAD(String tag, ImapSearch i4search, boolean byUID) throws IOException, ImapException {
/* 3464 */     if (!checkState(tag, State.SELECTED)) {
/* 3465 */       return true;
/*      */     }
/* 3467 */     ImapFolder i4folder = getSelectedFolder();
/* 3468 */     if (i4folder == null) {
/* 3469 */       throw new ImapSessionClosedException();
/*      */     }
/* 3471 */     boolean requiresMODSEQ = i4search.requiresMODSEQ();
/* 3472 */     if (requiresMODSEQ) {
/* 3473 */       activateExtension(ImapExtension.CONDSTORE);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 3481 */     if ((requiresMODSEQ) && (!sessionActivated(ImapExtension.CONDSTORE))) {
/* 3482 */       throw new ImapParseException(tag, "NOMODSEQ", "cannot THREAD MODSEQ in this mailbox", true);
/*      */     }
/* 3484 */     LinkedHashMap<Integer, List<ImapMessage>> threads = new LinkedHashMap();
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */     try
/*      */     {
/* 3491 */       ZimbraQueryResults zqr = runSearch(i4search, i4folder, SortBy.DATE_ASC, SearchParams.Fetch.PARENT);
/*      */       try {
/* 3493 */         for (ZimbraHit hit = zqr.getNext(); hit != null; hit = zqr.getNext()) {
/* 3494 */           ImapMessage i4msg = i4folder.getById(hit.getItemId());
/* 3495 */           if ((i4msg != null) && (!i4msg.isExpunged()))
/*      */           {
/*      */ 
/* 3498 */             int parentId = hit.getParentId();
/* 3499 */             if (parentId <= 0) {
/* 3500 */               threads.put(Integer.valueOf(-i4msg.msgId), Arrays.asList(new ImapMessage[] { i4msg }));
/*      */             }
/*      */             else
/*      */             {
/* 3504 */               List<ImapMessage> contents = (List)threads.get(Integer.valueOf(parentId));
/* 3505 */               if (contents == null) {
/* 3506 */                 (contents = new LinkedList()).add(i4msg);
/* 3507 */                 threads.put(Integer.valueOf(parentId), contents);
/*      */               } else {
/* 3509 */                 contents.add(i4msg);
/*      */               }
/*      */             }
/*      */           }
/* 3513 */         } } finally { zqr.close();
/*      */       }
/*      */     } catch (ServiceException e) {
/* 3516 */       ZimbraLog.imap.warn("THREAD failed", e);
/* 3517 */       sendNO(tag, "THREAD failed");
/* 3518 */       return true;
/*      */     }
/*      */     
/* 3521 */     StringBuilder result = new StringBuilder("THREAD");
/* 3522 */     if (!threads.isEmpty()) {
/* 3523 */       result.append(' ');
/* 3524 */       for (List<ImapMessage> thread : threads.values())
/*      */       {
/* 3526 */         Iterator<ImapMessage> it = thread.iterator();
/* 3527 */         result.append('(').append(getMessageId((ImapMessage)it.next(), byUID));
/* 3528 */         if (it.hasNext()) {
/* 3529 */           result.append(' ');
/* 3530 */           if (thread.size() == 2) {
/* 3531 */             result.append(getMessageId((ImapMessage)it.next(), byUID));
/*      */           } else {
/* 3533 */             while (it.hasNext()) {
/* 3534 */               result.append('(').append(getMessageId((ImapMessage)it.next(), byUID)).append(')');
/*      */             }
/*      */           }
/*      */         }
/* 3538 */         result.append(')');
/*      */       }
/*      */     }
/*      */     
/* 3542 */     sendUntagged(result.toString());
/* 3543 */     sendNotifications(false, false);
/* 3544 */     sendOK(tag, (byUID ? "UID " : "") + "THREAD completed");
/* 3545 */     return true;
/*      */   }
/*      */   
/*      */ 
/*      */   static final int FETCH_ENVELOPE = 4;
/*      */   
/*      */   static final int FETCH_FLAGS = 8;
/*      */   
/*      */   static final int FETCH_INTERNALDATE = 16;
/*      */   
/*      */   static final int FETCH_RFC822_SIZE = 32;
/*      */   static final int FETCH_BINARY_SIZE = 64;
/*      */   static final int FETCH_UID = 128;
/*      */   static final int FETCH_MODSEQ = 256;
/*      */   static final int FETCH_VANISHED = 512;
/*      */   static final int FETCH_MARK_READ = 4096;
/*      */   static final int FETCH_FROM_CACHE = 136;
/*      */   static final int FETCH_FROM_MIME = 7;
/*      */   static final int FETCH_FAST = 56;
/*      */   static final int FETCH_ALL = 60;
/*      */   static final int FETCH_FULL = 61;
/*      */   boolean doFETCH(String tag, String sequenceSet, int attributes, List<ImapPartSpecifier> parts, boolean byUID, int changedSince)
/*      */     throws IOException, ImapException
/*      */   {
/* 3569 */     checkCommandThrottle(new FetchCommand(sequenceSet, attributes, parts));
/* 3570 */     return fetch(tag, sequenceSet, attributes, parts, byUID, changedSince, true);
/*      */   }
/*      */   
/*      */   boolean fetch(String tag, String sequenceSet, int attributes, List<ImapPartSpecifier> parts, boolean byUID, int changedSince, boolean standalone) throws IOException, ImapException
/*      */   {
/* 3575 */     return fetch(tag, sequenceSet, attributes, parts, byUID, changedSince, standalone, false);
/*      */   }
/*      */   
/*      */ 
/*      */   boolean fetch(String tag, String sequenceSet, int attributes, List<ImapPartSpecifier> parts, boolean byUID, int changedSince, boolean standalone, boolean allowOutOfRangeMsgSeq)
/*      */     throws IOException, ImapException
/*      */   {
/* 3582 */     if (!checkState(tag, State.SELECTED)) {
/* 3583 */       return true;
/*      */     }
/* 3585 */     ImapFolder i4folder = getSelectedFolder();
/* 3586 */     if (i4folder == null) {
/* 3587 */       throw new ImapSessionClosedException();
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 3592 */     if (byUID) {
/* 3593 */       attributes |= 0x80;
/*      */     }
/* 3595 */     String command = byUID ? "UID FETCH" : "FETCH";
/* 3596 */     boolean markRead = (i4folder.isWritable()) && ((attributes & 0x1000) != 0);
/*      */     
/*      */ 
/*      */ 
/* 3600 */     if (((attributes & 0x200) != 0) && ((!byUID) || (changedSince < 0))) {
/* 3601 */       throw new ImapParseException(tag, "cannot specify VANISHED without CHANGEDSINCE");
/*      */     }
/* 3603 */     if (changedSince >= 0) {
/* 3604 */       attributes |= 0x100;
/*      */     }
/* 3606 */     if ((attributes & 0x100) != 0) {
/* 3607 */       activateExtension(ImapExtension.CONDSTORE);
/*      */     }
/* 3609 */     boolean modseqEnabled = sessionActivated(ImapExtension.CONDSTORE);
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 3617 */     if ((!modseqEnabled) && ((attributes & 0x100) != 0)) {
/* 3618 */       throw new ImapParseException(tag, "NOMODSEQ", "cannot FETCH MODSEQ in this mailbox", true);
/*      */     }
/* 3620 */     List<ImapPartSpecifier> fullMessage = new ArrayList();
/* 3621 */     Iterator<ImapPartSpecifier> it; if ((parts != null) && (!parts.isEmpty())) {
/* 3622 */       for (it = parts.iterator(); it.hasNext();) {
/* 3623 */         ImapPartSpecifier pspec = (ImapPartSpecifier)it.next();
/* 3624 */         if (pspec.isEntireMessage()) {
/* 3625 */           it.remove();fullMessage.add(pspec);
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 3631 */     Mailbox mbox = i4folder.getMailbox();
/* 3632 */     mbox.lock.lock(false);
/*      */     ImapMessage.ImapMessageSet i4set;
/* 3634 */     try { i4set = i4folder.getSubsequence(tag, sequenceSet, byUID, allowOutOfRangeMsgSeq, true);
/* 3635 */       i4set.remove(null);
/*      */     } finally {
/* 3637 */       mbox.lock.release();
/*      */     }
/*      */     
/*      */ 
/* 3641 */     if ((byUID) && ((attributes & 0x200) != 0)) {
/* 3642 */       int highwater = Integer.MAX_VALUE;
/*      */       try {
/* 3644 */         highwater = i4folder.getCurrentMODSEQ();
/*      */       } catch (ServiceException e) {}
/* 3646 */       if (highwater > changedSince) {
/* 3647 */         String vanished = i4folder.invertSubsequence(sequenceSet, true, i4set);
/* 3648 */         if (!vanished.isEmpty()) {
/* 3649 */           sendUntagged("VANISHED (EARLIER) " + vanished);
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 3656 */     if ((!byUID) && (!i4set.isEmpty())) {
/* 3657 */       boolean nonePresent = true;
/* 3658 */       for (ImapMessage i4msg : i4set) {
/* 3659 */         if (!i4msg.isExpunged()) {
/* 3660 */           nonePresent = false; break;
/*      */         }
/*      */       }
/* 3663 */       if (nonePresent)
/*      */       {
/*      */ 
/* 3666 */         if (standalone) {
/* 3667 */           sendNO(tag, "all of the requested messages have been expunged");
/*      */         }
/* 3669 */         return true;
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 3674 */     if (changedSince >= 0) {
/*      */       try
/*      */       {
/* 3677 */         Object folderId = new HashSet(Arrays.asList(new Integer[] { Integer.valueOf(i4folder.getId()) }));
/* 3678 */         ImapMessage.ImapMessageSet modified = new ImapMessage.ImapMessageSet();
/* 3679 */         for (Iterator i$ = ((List)mbox.getModifiedItems(getContext(), changedSince, MailItem.Type.UNKNOWN, (Set)folderId).getFirst()).iterator(); i$.hasNext();) { int id = ((Integer)i$.next()).intValue();
/* 3680 */           ImapMessage i4msg = i4folder.getById(id);
/* 3681 */           if (i4msg != null) {
/* 3682 */             modified.add(i4msg);
/*      */           }
/*      */         }
/*      */         
/* 3686 */         i4set.retainAll(modified);
/*      */       } catch (ServiceException e) {
/* 3688 */         if (standalone) {
/* 3689 */           ZimbraLog.imap.warn(command + " failed", e);
/* 3690 */           sendNO(tag, command + " failed");
/* 3691 */           return canContinue(e);
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 3696 */     mbox.lock.lock();
/*      */     try {
/* 3698 */       if (i4folder.areTagsDirty()) {
/* 3699 */         sendUntagged("FLAGS (" + StringUtil.join(" ", i4folder.getFlagList(false)) + ')');
/* 3700 */         i4folder.setTagsDirty(false);
/*      */       }
/*      */     } finally {
/* 3703 */       mbox.lock.release();
/*      */     }
/* 3705 */     ReentrantLock lock = null;
/*      */     try {
/* 3707 */       for (ImapMessage i4msg : i4set) {
/* 3708 */         PrintStream result = new PrintStream(this.output, false, Charsets.UTF_8.name());
/*      */         try {
/* 3710 */           result.print("* " + i4msg.sequence + " FETCH (");
/*      */           
/* 3712 */           if (i4msg.isExpunged()) {
/* 3713 */             fetchStub(i4msg, i4folder, attributes, parts, fullMessage, result);
/*      */             
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 3829 */             if (result != null) {
/* 3830 */               result.write(41);
/* 3831 */               this.output.write(LINE_SEPARATOR_BYTES, 0, LINE_SEPARATOR_BYTES.length);
/* 3832 */               this.output.flush();
/*      */             }
/*      */           }
/*      */           else
/*      */           {
/* 3717 */             boolean markMessage = (markRead) && ((i4msg.flags & Flag.BITMASK_UNREAD) != 0);
/* 3718 */             boolean empty = true;
/* 3719 */             MailItem item = null;
/*      */             
/* 3721 */             if ((!fullMessage.isEmpty()) || ((parts != null) && (!parts.isEmpty())) || ((attributes & 0xFF77) != 0)) {
/* 3722 */               if ((lock == null) && (LC.imap_throttle_fetch.booleanValue())) {
/* 3723 */                 lock = this.commandThrottle.lock(this.credentials.getAccountId());
/*      */               }
/*      */               try {
/* 3726 */                 item = mbox.getItemById(getContext(), i4msg.msgId, i4msg.getType());
/*      */               }
/*      */               catch (MailServiceException.NoSuchItemException nsie) {
/* 3729 */                 i4folder.markMessageExpunged(i4msg);
/* 3730 */                 fetchStub(i4msg, i4folder, attributes, parts, fullMessage, result);
/*      */               }
/*      */               
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 3829 */               if (result == null) continue;
/* 3830 */               result.write(41);
/* 3831 */               this.output.write(LINE_SEPARATOR_BYTES, 0, LINE_SEPARATOR_BYTES.length);
/* 3832 */               this.output.flush(); continue;
/*      */             }
/* 3735 */             if ((attributes & 0x80) != 0) {
/* 3736 */               result.print((empty ? "" : " ") + "UID " + i4msg.imapUid);
/* 3737 */               empty = false;
/*      */             }
/* 3739 */             if ((attributes & 0x10) != 0) {
/* 3740 */               result.print((empty ? "" : " ") + "INTERNALDATE \"" + DateUtil.toImapDateTime(new Date(item.getDate())) + '"');
/*      */               
/* 3742 */               empty = false;
/*      */             }
/* 3744 */             if ((attributes & 0x20) != 0) {
/* 3745 */               result.print((empty ? "" : " ") + "RFC822.SIZE " + i4msg.getSize(item));
/* 3746 */               empty = false;
/*      */             }
/* 3748 */             if ((attributes & 0x40) != 0) {
/* 3749 */               result.print((empty ? "" : " ") + "BINARY.SIZE[] " + i4msg.getSize(item));
/* 3750 */               empty = false;
/*      */             }
/*      */             
/* 3753 */             if (!fullMessage.isEmpty()) {
/* 3754 */               for (ImapPartSpecifier pspec : fullMessage) {
/* 3755 */                 result.print(empty ? "" : " ");
/* 3756 */                 pspec.write(result, this.output, item);
/* 3757 */                 empty = false;
/*      */               }
/*      */             }
/*      */             MimeMessage mm;
/* 3761 */             if (((parts != null) && (!parts.isEmpty())) || ((attributes & 0x7) != 0)) {
/* 3762 */               mm = ImapMessage.getMimeMessage(item);
/* 3763 */               if ((attributes & 0x1) != 0) {
/* 3764 */                 result.print(empty ? "" : " ");
/* 3765 */                 result.print("BODY ");
/* 3766 */                 ImapMessage.serializeStructure(result, mm, false);
/* 3767 */                 empty = false;
/*      */               }
/* 3769 */               if ((attributes & 0x2) != 0) {
/* 3770 */                 result.print(empty ? "" : " ");
/* 3771 */                 result.print("BODYSTRUCTURE ");
/* 3772 */                 ImapMessage.serializeStructure(result, mm, true);
/* 3773 */                 empty = false;
/*      */               }
/* 3775 */               if ((attributes & 0x4) != 0) {
/* 3776 */                 result.print(empty ? "" : " ");
/* 3777 */                 result.print("ENVELOPE ");
/* 3778 */                 ImapMessage.serializeEnvelope(result, mm);
/* 3779 */                 empty = false;
/*      */               }
/* 3781 */               if (parts != null) {
/* 3782 */                 for (ImapPartSpecifier pspec : parts) {
/* 3783 */                   result.print(empty ? "" : " ");
/* 3784 */                   pspec.write(result, this.output, mm);
/* 3785 */                   empty = false;
/*      */                 }
/*      */               }
/*      */             }
/*      */             
/*      */ 
/*      */ 
/*      */ 
/* 3793 */             if (markMessage) {
/* 3794 */               mbox.alterTag(getContext(), i4msg.msgId, i4msg.getType(), Flag.FlagInfo.UNREAD, false, null);
/*      */             }
/* 3796 */             ImapFolder.DirtyMessage unsolicited = i4folder.undirtyMessage(i4msg);
/* 3797 */             if (((attributes & 0x8) != 0) || (unsolicited != null)) {
/* 3798 */               result.print(empty ? "" : " ");
/* 3799 */               result.print(i4msg.getFlags(i4folder));
/* 3800 */               empty = false;
/*      */             }
/*      */             
/*      */ 
/*      */ 
/*      */ 
/* 3806 */             if (((attributes & 0x100) != 0) || ((modseqEnabled) && (unsolicited != null))) {
/* 3807 */               int modseq = unsolicited == null ? i4msg.getModseq(item) : unsolicited.modseq;
/* 3808 */               result.print((empty ? "" : " ") + "MODSEQ (" + modseq + ')');empty = false;
/*      */             }
/*      */           }
/*      */         } catch (ImapPartSpecifier.BinaryDecodingException e) {
/* 3812 */           result = null;
/* 3813 */           throw new ImapParseException(tag, "UNKNOWN-CTE", command + "failed: unknown content-type-encoding", false);
/*      */         } catch (ServiceException e) {
/* 3815 */           Throwable cause = e.getCause();
/* 3816 */           if ((cause instanceof IOException)) {
/* 3817 */             fetchException(cause);
/*      */           } else {
/* 3819 */             ZimbraLog.imap.warn("ignoring error during " + command + ": ", e);
/*      */             
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 3829 */             if (result == null) continue;
/* 3830 */             result.write(41);
/* 3831 */             this.output.write(LINE_SEPARATOR_BYTES, 0, LINE_SEPARATOR_BYTES.length);
/* 3832 */             this.output.flush(); continue;
/*      */           }
/*      */         }
/*      */         catch (MessagingException e)
/*      */         {
/* 3823 */           ZimbraLog.imap.warn("ignoring error during " + command + ": ", e);
/*      */           
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 3829 */           if (result != null) {
/* 3830 */             result.write(41);
/* 3831 */             this.output.write(LINE_SEPARATOR_BYTES, 0, LINE_SEPARATOR_BYTES.length);
/* 3832 */             this.output.flush();
/*      */           }
/*      */         }
/*      */         catch (IOException ioe)
/*      */         {
/* 3826 */           fetchException(ioe);
/*      */         }
/*      */         finally {
/* 3829 */           if (result != null) {
/* 3830 */             result.write(41);
/* 3831 */             this.output.write(LINE_SEPARATOR_BYTES, 0, LINE_SEPARATOR_BYTES.length);
/* 3832 */             this.output.flush();
/*      */           }
/*      */         }
/*      */       }
/*      */     } finally {
/* 3837 */       if (lock != null) {
/* 3838 */         lock.unlock();
/*      */       }
/*      */     }
/* 3841 */     if (standalone) {
/* 3842 */       sendNotifications(byUID, false);
/* 3843 */       sendOK(tag, command + " completed");
/*      */     }
/* 3845 */     return true;
/*      */   }
/*      */   
/*      */   private void fetchException(Throwable cause) throws ImapIOException {
/* 3849 */     if (ZimbraLog.imap.isDebugEnabled()) {
/* 3850 */       ZimbraLog.imap.debug("IOException fetching IMAP message, closing connection", cause);
/*      */     } else {
/* 3852 */       ZimbraLog.imap.warn("IOException fetching IMAP message, closing connection");
/*      */     }
/* 3854 */     throw new ImapIOException("IOException during message fetch", cause);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private void fetchStub(ImapMessage i4msg, ImapFolder i4folder, int attributes, List<ImapPartSpecifier> parts, List<ImapPartSpecifier> fullMessage, PrintStream result)
/*      */     throws ServiceException
/*      */   {
/* 3864 */     boolean empty = true;
/*      */     
/* 3866 */     if ((attributes & 0x80) != 0) {
/* 3867 */       result.print((empty ? "" : " ") + "UID " + i4msg.imapUid);
/* 3868 */       empty = false;
/*      */     }
/* 3870 */     if ((attributes & 0x10) != 0) {
/* 3871 */       result.print((empty ? "" : " ") + "INTERNALDATE \"01-Jan-1970 00:00:00 +0000\"");
/* 3872 */       empty = false;
/*      */     }
/* 3874 */     if ((attributes & 0x20) != 0) {
/* 3875 */       result.print((empty ? "" : " ") + "RFC822.SIZE 0");
/* 3876 */       empty = false;
/*      */     }
/* 3878 */     if ((attributes & 0x40) != 0) {
/* 3879 */       result.print((empty ? "" : " ") + "BINARY.SIZE[] 0");
/* 3880 */       empty = false;
/*      */     }
/*      */     
/* 3883 */     if (!fullMessage.isEmpty()) {
/* 3884 */       for (ImapPartSpecifier pspec : fullMessage) {
/* 3885 */         result.print((empty ? "" : " ") + pspec + " \"\"");
/* 3886 */         empty = false;
/*      */       }
/*      */     }
/* 3889 */     if ((attributes & 0x1) != 0) {
/* 3890 */       result.print((empty ? "" : " ") + "BODY (\"TEXT\" \"PLAIN\" NIL NIL NIL \"7BIT\" 0 0)");
/* 3891 */       empty = false;
/*      */     }
/* 3893 */     if ((attributes & 0x2) != 0) {
/* 3894 */       result.print((empty ? "" : " ") + "BODYSTRUCTURE (\"TEXT\" \"PLAIN\" NIL NIL NIL \"7BIT\" 0 0)");
/* 3895 */       empty = false;
/*      */     }
/* 3897 */     if ((attributes & 0x4) != 0) {
/* 3898 */       result.print((empty ? "" : " ") + "ENVELOPE (NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)");
/* 3899 */       empty = false;
/*      */     }
/* 3901 */     if (parts != null) {
/* 3902 */       for (Iterator i$ = parts.iterator(); i$.hasNext(); 
/*      */           
/*      */ 
/*      */ 
/* 3906 */           empty = false)
/*      */       {
/* 3902 */         ImapPartSpecifier pspec = (ImapPartSpecifier)i$.next();
/*      */         
/* 3904 */         String pnum = pspec.getSectionPart();
/* 3905 */         String value = (pnum.equals("")) || (pnum.equals("1")) ? "\"\"" : pspec.getCommand().equals("BINARY.SIZE") ? "0" : "NIL";
/* 3906 */         result.print((empty ? "" : " ") + pspec + ' ' + value);
/*      */       }
/*      */     }
/*      */     
/* 3910 */     if ((attributes & 0x8) != 0) {
/* 3911 */       result.print((empty ? "" : " ") + "FLAGS ()");
/* 3912 */       empty = false;
/*      */     }
/* 3914 */     if ((attributes & 0x100) != 0) {
/* 3915 */       result.print((empty ? "" : " ") + "MODSEQ (" + i4folder.getCurrentMODSEQ() + ')');
/* 3916 */       empty = false;
/*      */     }
/*      */     
/*      */ 
/* 3920 */     i4folder.undirtyMessage(i4msg);
/*      */   }
/*      */   
/* 3923 */   static enum StoreAction { REPLACE,  ADD,  REMOVE;
/*      */     private StoreAction() {} }
/* 3925 */   private final int SUGGESTED_BATCH_SIZE = 100;
/*      */   
/*      */   boolean doSTORE(String tag, String sequenceSet, List<String> flagNames, StoreAction operation, boolean silent, int modseq, boolean byUID) throws IOException, ImapException
/*      */   {
/* 3929 */     checkCommandThrottle(new StoreCommand(sequenceSet, flagNames, operation, modseq));
/* 3930 */     if (!checkState(tag, State.SELECTED)) {
/* 3931 */       return true;
/*      */     }
/*      */     
/* 3934 */     ImapFolder i4folder = getSelectedFolder();
/* 3935 */     if (i4folder == null) {
/* 3936 */       throw new ImapSessionClosedException();
/*      */     }
/* 3938 */     if (!i4folder.isWritable()) {
/* 3939 */       sendNO(tag, "mailbox selected READ-ONLY");
/* 3940 */       return true;
/*      */     }
/*      */     
/* 3943 */     if (modseq >= 0) {
/* 3944 */       activateExtension(ImapExtension.CONDSTORE);
/*      */     }
/* 3946 */     boolean modseqEnabled = sessionActivated(ImapExtension.CONDSTORE);
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 3952 */     if ((!modseqEnabled) && (modseq >= 0)) {
/* 3953 */       throw new ImapParseException(tag, "NOMODSEQ", "cannot STORE UNCHANGEDSINCE in this mailbox", true);
/*      */     }
/* 3955 */     ImapMessage.ImapMessageSet modifyConflicts = modseqEnabled ? new ImapMessage.ImapMessageSet() : null;
/*      */     
/* 3957 */     String command = byUID ? "UID STORE" : "STORE";
/* 3958 */     List<Tag> newTags = operation != StoreAction.REMOVE ? new ArrayList() : null;
/* 3959 */     Mailbox mbox = this.selectedFolder.getMailbox();
/*      */     
/*      */ 
/* 3962 */     mbox.lock.lock();
/*      */     Set<ImapMessage> i4set;
/* 3964 */     try { i4set = i4folder.getSubsequence(tag, sequenceSet, byUID);
/*      */     } finally {
/* 3966 */       mbox.lock.release();
/*      */     }
/* 3968 */     boolean allPresent = (byUID) || (!i4set.contains(null));
/* 3969 */     i4set.remove(null);
/*      */     
/*      */     try
/*      */     {
/* 3973 */       List<String> tags = Lists.newArrayList();
/*      */       
/*      */ 
/* 3976 */       Set<ImapFlagCache.ImapFlag> i4flags = new HashSet(flagNames.size());
/*      */       
/* 3978 */       for (String name : flagNames) {
/* 3979 */         ImapFlagCache.ImapFlag i4flag = i4folder.getFlagByName(name);
/* 3980 */         if (i4flag == null) {
/* 3981 */           tags.add(name);
/*      */         } else {
/* 3983 */           if (i4flag.mId > 0) {
/* 3984 */             tags.add(i4flag.mName);
/*      */           } else {
/* 3986 */             i4flags.add(i4flag);
/*      */           }
/* 3988 */           if (operation != StoreAction.REMOVE) {
/* 3989 */             if (i4flag.mId == Flag.ID_DELETED) {
/* 3990 */               if (!i4folder.getPath().isWritable((short)8)) {
/* 3991 */                 throw ServiceException.PERM_DENIED("you do not have permission to set the \\Deleted flag");
/*      */               }
/* 3993 */             } else if ((i4flag.mPermanent) && 
/* 3994 */               (!i4folder.getPath().isWritable((short)2))) {
/* 3995 */               throw ServiceException.PERM_DENIED("you do not have permission to set the " + i4flag.mName + " flag");
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */       
/*      */ 
/* 4002 */       int flags = Flag.BITMASK_UNREAD;short sflags = 0;
/* 4003 */       if (operation == StoreAction.REPLACE) {
/* 4004 */         for (ImapFlagCache.ImapFlag i4flag : i4flags) {
/* 4005 */           if (!i4flag.mPermanent) {
/* 4006 */             sflags = (short)(byte)(int)(i4flag.mPositive ? sflags | i4flag.mBitmask : sflags & (i4flag.mBitmask ^ 0xFFFFFFFFFFFFFFFF));
/*      */           } else {
/* 4008 */             flags = (int)(i4flag.mPositive ? flags | i4flag.mBitmask : flags & (i4flag.mBitmask ^ 0xFFFFFFFFFFFFFFFF));
/*      */           }
/*      */         }
/*      */       }
/*      */       
/* 4013 */       long checkpoint = System.currentTimeMillis();
/*      */       
/* 4015 */       int i = 0;
/* 4016 */       List<ImapMessage> i4list = new ArrayList(100);
/* 4017 */       List<Integer> idlist = new ArrayList(100);
/* 4018 */       for (Iterator i$ = i4set.iterator(); i$.hasNext(); 
/*      */           
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 4108 */           idlist.clear())
/*      */       {
/*      */         label633:
/* 4018 */         ImapMessage msg = (ImapMessage)i$.next();
/*      */         
/* 4020 */         i4list.add(msg);idlist.add(Integer.valueOf(msg.msgId));
/* 4021 */         i++; if ((i % 100 != 0) && (i != i4set.size())) {
/*      */           break label633;
/*      */         }
/* 4024 */         mbox.lock.lock();
/*      */         try {
/* 4026 */           if (modseq >= 0) {
/* 4027 */             MailItem[] items = mbox.getItemById(getContext(), idlist, MailItem.Type.UNKNOWN);
/* 4028 */             for (int idx = items.length - 1; idx >= 0; idx--) {
/* 4029 */               ImapMessage i4msg = (ImapMessage)i4list.get(idx);
/* 4030 */               if (i4msg.getModseq(items[idx]) > modseq) {
/* 4031 */                 modifyConflicts.add(i4msg);
/* 4032 */                 i4list.remove(idx);idlist.remove(idx);
/* 4033 */                 allPresent = false;
/*      */               }
/*      */             }
/*      */           }
/*      */           
/*      */           try
/*      */           {
/* 4040 */             if ((silent) && (!modseqEnabled)) {
/* 4041 */               i4folder.disableNotifications();
/*      */             }
/* 4043 */             if (operation == StoreAction.REPLACE)
/*      */             {
/* 4045 */               mbox.setTags(getContext(), ArrayUtil.toIntArray(idlist), MailItem.Type.UNKNOWN, flags, (String[])tags.toArray(new String[tags.size()]), null);
/*      */               
/* 4047 */               for (ImapMessage i4msg : i4list) {
/* 4048 */                 i4msg.setSessionFlags(sflags, i4folder);
/*      */               }
/*      */             } else {
/* 4051 */               for (Iterator i$ = i4flags.iterator(); i$.hasNext();) { i4flag = (ImapFlagCache.ImapFlag)i$.next();
/* 4052 */                 add = (operation == StoreAction.ADD ? 1 : 0) ^ (!i4flag.mPositive ? 1 : 0);
/* 4053 */                 if (i4flag.mPermanent)
/*      */                 {
/* 4055 */                   mbox.alterTag(getContext(), ArrayUtil.toIntArray(idlist), MailItem.Type.UNKNOWN, i4flag.mName, add, null);
/*      */                 }
/*      */                 else
/* 4058 */                   for (ImapMessage i4msg : i4list)
/* 4059 */                     i4msg.setSessionFlags((short)(int)(add ? i4msg.sflags | i4flag.mBitmask : i4msg.sflags & (i4flag.mBitmask ^ 0xFFFFFFFFFFFFFFFF)), i4folder);
/*      */               }
/*      */               ImapFlagCache.ImapFlag i4flag;
/*      */               boolean add;
/* 4063 */               add = operation == StoreAction.ADD;
/*      */               
/* 4065 */               for (String tagName : tags) {
/* 4066 */                 mbox.alterTag(getContext(), ArrayUtil.toIntArray(idlist), MailItem.Type.UNKNOWN, tagName, add, null);
/*      */               }
/*      */             }
/*      */           } finally {
/*      */             boolean add;
/* 4071 */             i4folder.enableNotifications();
/*      */           }
/*      */         } finally {
/* 4074 */           mbox.lock.release();
/*      */         }
/*      */         
/* 4077 */         if ((!silent) || (modseqEnabled)) {
/* 4078 */           for (ImapMessage i4msg : i4list) {
/* 4079 */             ImapFolder.DirtyMessage dirty = i4folder.undirtyMessage(i4msg);
/* 4080 */             if ((!silent) || ((dirty != null) && (dirty.modseq > 0)))
/*      */             {
/*      */ 
/* 4083 */               StringBuilder ntfn = new StringBuilder();
/* 4084 */               boolean empty = true;
/* 4085 */               ntfn.append(i4msg.sequence).append(" FETCH (");
/* 4086 */               if (!silent) {
/* 4087 */                 ntfn.append(i4msg.getFlags(i4folder));empty = false;
/*      */               }
/*      */               
/*      */ 
/*      */ 
/* 4092 */               if (byUID) {
/* 4093 */                 ntfn.append(empty ? "" : " ").append("UID ").append(i4msg.imapUid);empty = false;
/*      */               }
/* 4095 */               if ((dirty != null) && (dirty.modseq > 0) && (modseqEnabled)) {
/* 4096 */                 ntfn.append(empty ? "" : " ").append("MODSEQ (").append(dirty.modseq).append(')');empty = false;
/*      */               }
/* 4098 */               sendUntagged(')');
/*      */             }
/*      */           }
/*      */         } else {
/* 4102 */           long now = System.currentTimeMillis();
/* 4103 */           if (now - checkpoint > 15000L) {
/* 4104 */             sendIdleUntagged();checkpoint = now;
/*      */           }
/*      */         }
/*      */         
/* 4108 */         i4list.clear();
/*      */       }
/*      */     } catch (ServiceException e) {
/* 4111 */       deleteTags(newTags);
/* 4112 */       if (e.getCode().equals("mail.INVALID_NAME")) {
/* 4113 */         ZimbraLog.imap.info("%s failed: %s", new Object[] { command, e.getMessage() });
/*      */       } else {
/* 4115 */         ZimbraLog.imap.warn("%s failed", command, e);
/*      */       }
/* 4117 */       sendNO(tag, command + " failed");
/* 4118 */       return canContinue(e);
/*      */     }
/*      */     
/* 4121 */     boolean hadConflicts = (modifyConflicts != null) && (!modifyConflicts.isEmpty());
/* 4122 */     String conflicts = hadConflicts ? " [MODIFIED " + ImapFolder.encodeSubsequence(modifyConflicts, byUID) + ']' : "";
/*      */     
/* 4124 */     sendNotifications(byUID, false);
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 4130 */     if ((silent) || (allPresent)) {
/* 4131 */       sendOK(tag, command + conflicts + " completed");
/*      */     } else {
/* 4133 */       sendNO(tag, command + conflicts + " completed");
/*      */     }
/* 4135 */     return true;
/*      */   }
/*      */   
/* 4138 */   private final int SUGGESTED_COPY_BATCH_SIZE = 50;
/*      */   
/*      */   boolean doCOPY(String tag, String sequenceSet, ImapPath path, boolean byUID) throws IOException, ImapException {
/* 4141 */     checkCommandThrottle(new CopyCommand(sequenceSet, path));
/* 4142 */     if (!checkState(tag, State.SELECTED)) {
/* 4143 */       return true;
/*      */     }
/* 4145 */     String command = byUID ? "UID COPY" : "COPY";
/* 4146 */     String copyuid = "";
/* 4147 */     List<MailItem> copies = new ArrayList();
/*      */     
/* 4149 */     ImapFolder i4folder = getSelectedFolder();
/* 4150 */     if (i4folder == null) {
/* 4151 */       throw new ImapSessionClosedException();
/*      */     }
/* 4153 */     Mailbox mbox = i4folder.getMailbox();
/*      */     
/*      */ 
/* 4156 */     mbox.lock.lock();
/*      */     Set<ImapMessage> i4set;
/* 4158 */     try { i4set = i4folder.getSubsequence(tag, sequenceSet, byUID);
/*      */     } finally {
/* 4160 */       mbox.lock.release();
/*      */     }
/*      */     
/*      */ 
/* 4164 */     if ((!byUID) && (i4set.contains(null))) {
/* 4165 */       sendNO(tag, "COPY rejected because some of the requested messages were expunged");
/* 4166 */       return true;
/*      */     }
/* 4168 */     i4set.remove(null);
/*      */     try
/*      */     {
/* 4171 */       if (!path.isVisible())
/* 4172 */         throw ImapServiceException.FOLDER_NOT_VISIBLE(path.asImapPath());
/* 4173 */       if (!path.isWritable((short)4)) {
/* 4174 */         throw ImapServiceException.FOLDER_NOT_WRITABLE(path.asImapPath());
/*      */       }
/* 4176 */       Object mboxobj = path.getOwnerMailbox();
/*      */       
/* 4178 */       boolean sameMailbox = false;
/*      */       
/*      */       int uvv;
/*      */       
/* 4182 */       if ((mboxobj instanceof Mailbox)) {
/* 4183 */         sameMailbox = mbox.getAccountId().equalsIgnoreCase(((Mailbox)mboxobj).getAccountId());
/* 4184 */         Folder folder = (Folder)path.getFolder();
/* 4185 */         ItemId iidTarget = new ItemId(folder);
/* 4186 */         uvv = ImapFolder.getUIDValidity(folder); } else { int uvv;
/* 4187 */         if ((mboxobj instanceof ZMailbox)) {
/* 4188 */           ZFolder zfolder = (ZFolder)path.getFolder();
/* 4189 */           ItemId iidTarget = new ItemId(zfolder.getId(), path.getOwnerAccount().getId());
/* 4190 */           uvv = ImapFolder.getUIDValidity(zfolder);
/*      */         } else {
/* 4192 */           throw AccountServiceException.NO_SUCH_ACCOUNT(path.getOwner()); } }
/*      */       int uvv;
/*      */       ItemId iidTarget;
/* 4195 */       long checkpoint = System.currentTimeMillis();
/* 4196 */       List<Integer> srcUIDs = extensionEnabled("UIDPLUS") ? new ArrayList() : null;
/* 4197 */       List<Integer> copyUIDs = extensionEnabled("UIDPLUS") ? new ArrayList() : null;
/*      */       
/* 4199 */       int i = 0;
/* 4200 */       List<ImapMessage> i4list = new ArrayList(50);
/* 4201 */       List<Integer> idlist = new ArrayList(50);
/* 4202 */       List<Integer> createdList = new ArrayList(50);
/* 4203 */       for (ImapMessage i4msg : i4set)
/*      */       {
/* 4205 */         i4list.add(i4msg);idlist.add(Integer.valueOf(i4msg.msgId));
/* 4206 */         i++; if ((i % 50 == 0) || (i == i4set.size()))
/*      */         {
/*      */ 
/* 4209 */           if (sameMailbox) {
/*      */             List<MailItem> copyMsgs;
/*      */             try {
/* 4212 */               MailItem.Type type = MailItem.Type.UNKNOWN;
/* 4213 */               int[] mItemIds = new int[i4list.size()];
/* 4214 */               int counter = 0;
/* 4215 */               for (ImapMessage curMsg : i4list) {
/* 4216 */                 mItemIds[(counter++)] = curMsg.msgId;
/* 4217 */                 if (counter == 1) {
/* 4218 */                   type = curMsg.getType();
/* 4219 */                 } else if (curMsg.getType() != type) {
/* 4220 */                   type = MailItem.Type.UNKNOWN;
/*      */                 }
/*      */               }
/* 4223 */               copyMsgs = mbox.imapCopy(getContext(), mItemIds, type, iidTarget.getId());
/*      */             } catch (IOException e) {
/* 4225 */               throw ServiceException.FAILURE("Caught IOException executing " + this, e);
/*      */             }
/*      */             
/* 4228 */             copies.addAll(copyMsgs);
/* 4229 */             for (MailItem target : copyMsgs) {
/* 4230 */               createdList.add(Integer.valueOf(target.getImapUid()));
/*      */             }
/*      */           } else {
/* 4233 */             ItemActionHelper op = ItemActionHelper.COPY(getContext(), mbox, null, idlist, MailItem.Type.UNKNOWN, null, iidTarget);
/* 4234 */             for (String target : op.getCreatedIds()) {
/* 4235 */               createdList.add(Integer.valueOf(new ItemId(target, this.selectedFolder.getAuthenticatedAccountId()).getId()));
/*      */             }
/*      */           }
/*      */           
/* 4239 */           if (createdList.size() != i4list.size()) {
/* 4240 */             throw ServiceException.FAILURE("mismatch between original and target count during IMAP COPY", null);
/*      */           }
/* 4242 */           if (srcUIDs != null) {
/* 4243 */             for (ImapMessage source : i4list) {
/* 4244 */               srcUIDs.add(Integer.valueOf(source.imapUid));
/*      */             }
/* 4246 */             for (Integer target : createdList) {
/* 4247 */               copyUIDs.add(target);
/*      */             }
/*      */           }
/*      */           
/* 4251 */           i4list.clear();idlist.clear();createdList.clear();
/*      */           
/*      */ 
/* 4254 */           long now = System.currentTimeMillis();
/* 4255 */           if (now - checkpoint > 15000L) {
/* 4256 */             sendIdleUntagged();checkpoint = now;
/*      */           }
/*      */         }
/*      */       }
/* 4260 */       if ((uvv > 0) && (srcUIDs != null) && (srcUIDs.size() > 0)) {
/* 4261 */         copyuid = "[COPYUID " + uvv + ' ' + ImapFolder.encodeSubsequence(srcUIDs) + ' ' + ImapFolder.encodeSubsequence(copyUIDs) + "] ";
/*      */       }
/*      */       
/*      */     }
/*      */     catch (IOException e)
/*      */     {
/* 4267 */       ZimbraLog.imap.warn("%s failed", command, e);
/* 4268 */       sendNO(tag, command + " failed");
/* 4269 */       return true;
/*      */     }
/*      */     catch (ServiceException e)
/*      */     {
/* 4273 */       String rcode = "";
/* 4274 */       if (e.getCode().equals("mail.NO_SUCH_FOLDER")) {
/* 4275 */         ZimbraLog.imap.info("%s failed: no such folder: %s", new Object[] { command, path });
/* 4276 */         if (path.isCreatable()) {
/* 4277 */           rcode = "[TRYCREATE] ";
/*      */         }
/* 4279 */       } else if (e.getCode().equals("imap.FOLDER_NOT_VISIBLE")) {
/* 4280 */         ZimbraLog.imap.info("%s failed: folder not visible: %s", new Object[] { command, path });
/* 4281 */       } else if (e.getCode().equals("imap.FOLDER_NOT_WRITABLE")) {
/* 4282 */         ZimbraLog.imap.info("%s failed: folder not writable: %s", new Object[] { command, path });
/*      */       } else {
/* 4284 */         ZimbraLog.imap.warn("%s failed", command, e);
/*      */       }
/* 4286 */       sendNO(tag, rcode + command + " failed");
/* 4287 */       return canContinue(e);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/* 4293 */     sendNotifications(true, false);
/* 4294 */     sendOK(tag, copyuid + command + " completed");
/* 4295 */     return true;
/*      */   }
/*      */   
/*      */   private void checkCommandThrottle(ImapCommand command) throws ImapThrottledException {
/* 4299 */     if ((this.reqThrottle.isIpWhitelisted(getOrigRemoteIp())) || (this.reqThrottle.isIpWhitelisted(getRemoteIp())))
/* 4300 */       return;
/* 4301 */     if (this.commandThrottle.isCommandThrottled(command)) {
/* 4302 */       ZimbraLog.imap.warn("too many repeated %s requests dropping connection", new Object[] { command.getClass().getSimpleName().toUpperCase() });
/* 4303 */       throw new ImapThrottledException("too many repeated " + command.getClass().getSimpleName() + " requests");
/*      */     }
/*      */   }
/*      */   
/*      */   public void sendNotifications(boolean notifyExpunges, boolean flush) throws IOException {
/* 4308 */     ImapProxy proxy = this.imapProxy;
/* 4309 */     if (proxy != null) {
/* 4310 */       proxy.fetchNotifications();
/* 4311 */       return;
/*      */     }
/*      */     
/* 4314 */     ImapSession i4selected = getCurrentSession();
/* 4315 */     if ((i4selected == null) || (!i4selected.hasNotifications())) {
/* 4316 */       return;
/*      */     }
/* 4318 */     Mailbox mbox = i4selected.getMailbox();
/* 4319 */     if (mbox == null) {
/*      */       return;
/*      */     }
/*      */     ImapFolder i4folder;
/*      */     try {
/* 4324 */       i4folder = i4selected.getImapFolder();
/*      */     } catch (ImapSessionClosedException e) {
/* 4326 */       return;
/*      */     }
/*      */     
/* 4329 */     List<String> notifications = new ArrayList();
/*      */     
/* 4331 */     mbox.lock.lock();
/*      */     
/*      */     try
/*      */     {
/* 4335 */       if (i4folder.areTagsDirty()) {
/* 4336 */         notifications.add("FLAGS (" + StringUtil.join(" ", i4folder.getFlagList(false)) + ')');
/* 4337 */         i4folder.setTagsDirty(false);
/*      */       }
/*      */       
/* 4340 */       int oldRecent = i4folder.getRecentCount();
/* 4341 */       boolean removed = false;
/* 4342 */       boolean received = i4folder.checkpointSize();
/* 4343 */       if (notifyExpunges) {
/* 4344 */         List<Integer> expunged = i4folder.collapseExpunged(sessionActivated(ImapExtension.QRESYNC));
/* 4345 */         removed = !expunged.isEmpty();
/* 4346 */         if (removed) {
/* 4347 */           if (sessionActivated(ImapExtension.QRESYNC)) {
/* 4348 */             notifications.add("VANISHED " + ImapFolder.encodeSubsequence(expunged));
/*      */           } else {
/* 4350 */             for (Integer index : expunged) {
/* 4351 */               notifications.add(index + " EXPUNGE");
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/* 4356 */       i4folder.checkpointSize();
/*      */       
/*      */ 
/* 4359 */       boolean sendModseq = sessionActivated(ImapExtension.CONDSTORE);
/* 4360 */       for (Iterator<ImapFolder.DirtyMessage> it = i4folder.dirtyIterator(); it.hasNext();) {
/* 4361 */         ImapFolder.DirtyMessage dirty = (ImapFolder.DirtyMessage)it.next();
/* 4362 */         if (dirty.i4msg.isAdded()) {
/* 4363 */           dirty.i4msg.setAdded(false);
/*      */         } else {
/* 4365 */           notifications.add(dirty.i4msg.sequence + " FETCH (" + dirty.i4msg.getFlags(i4folder) + ((sendModseq) && (dirty.modseq > 0) ? " MODSEQ (" + dirty.modseq + ')' : "") + ')');
/*      */         }
/*      */       }
/*      */       
/* 4369 */       i4folder.clearDirty();
/*      */       
/* 4371 */       if ((received) || (removed)) {
/* 4372 */         notifications.add(i4folder.getSize() + " EXISTS");
/*      */       }
/* 4374 */       if ((received) || (oldRecent != i4folder.getRecentCount())) {
/* 4375 */         notifications.add(i4folder.getRecentCount() + " RECENT");
/*      */       }
/*      */     } finally {
/* 4378 */       mbox.lock.release();
/*      */     }
/*      */     
/*      */ 
/* 4382 */     for (String ntfn : notifications) {
/* 4383 */       sendUntagged(ntfn);
/*      */     }
/* 4385 */     if (flush) {
/* 4386 */       this.output.flush();
/*      */     }
/*      */   }
/*      */   
/*      */   void sendIdleUntagged() throws IOException {
/* 4391 */     sendUntagged("NOOP", true);
/*      */   }
/*      */   
/*      */   void sendOK(String tag, String response) throws IOException {
/* 4395 */     this.consecutiveError = 0;
/* 4396 */     sendResponse(tag, "OK " + (Strings.isNullOrEmpty(response) ? " " : response), true);
/*      */   }
/*      */   
/*      */   void sendNO(String tag, String response) throws IOException {
/* 4400 */     this.consecutiveError += 1;
/* 4401 */     sendResponse(tag, "NO " + (Strings.isNullOrEmpty(response) ? " " : response), true);
/*      */   }
/*      */   
/*      */   void sendBAD(String tag, String response) throws IOException {
/* 4405 */     this.consecutiveError += 1;
/* 4406 */     ZimbraLog.imap.warn("BAD %s", new Object[] { response });
/* 4407 */     sendResponse(tag, "BAD " + (Strings.isNullOrEmpty(response) ? " " : response), true);
/*      */   }
/*      */   
/*      */   void sendBAD(String response) throws IOException {
/* 4411 */     this.consecutiveError += 1;
/* 4412 */     ZimbraLog.imap.warn("BAD %s", new Object[] { response });
/* 4413 */     sendResponse("*", "BAD " + (Strings.isNullOrEmpty(response) ? " " : response), true);
/*      */   }
/*      */   
/*      */   void sendUntagged(String response) throws IOException {
/* 4417 */     sendResponse("*", response, false);
/*      */   }
/*      */   
/*      */   void sendUntagged(String response, boolean flush) throws IOException {
/* 4421 */     sendResponse("*", response, flush);
/*      */   }
/*      */   
/*      */   void sendContinuation(String response) throws IOException {
/* 4425 */     sendResponse("+", response, true);
/*      */   }
/*      */   
/*      */   void sendGreeting() throws IOException {
/* 4429 */     sendUntagged("OK " + this.config.getGreeting(), true);
/*      */   }
/*      */   
/*      */   void sendBYE() {
/* 4433 */     sendBYE(this.config.getGoodbye());
/*      */   }
/*      */   
/*      */   void sendBYE(String msg) {
/*      */     try {
/* 4438 */       sendUntagged("BYE " + msg, true);
/*      */     }
/*      */     catch (IOException e) {}
/* 4441 */     this.goodbyeSent = true;
/*      */   }
/*      */   
/*      */   void sendResponse(String tag, String msg, boolean flush) throws IOException {
/* 4445 */     sendLine((tag == null ? "" : new StringBuilder().append(tag).append(' ').toString()) + (msg == null ? "" : msg), flush);
/*      */   }
/*      */   
/*      */   abstract void sendLine(String paramString, boolean paramBoolean)
/*      */     throws IOException;
/*      */   
/*      */   abstract void dropConnection(boolean paramBoolean);
/*      */   
/*      */   abstract void close();
/*      */   
/*      */   abstract void enableInactivityTimer()
/*      */     throws IOException;
/*      */   
/*      */   abstract void completeAuthentication()
/*      */     throws IOException;
/*      */   
/*      */   abstract boolean doSTARTTLS(String paramString)
/*      */     throws IOException;
/*      */   
/*      */   abstract InetSocketAddress getLocalAddress();
/*      */   
/*      */   abstract String getRemoteIp();
/*      */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/imap/ImapHandler.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */